mirror of
https://github.com/trafficlunar/tomodachi-share.git
synced 2026-05-13 13:17:45 +00:00
133 lines
4.2 KiB
TypeScript
133 lines
4.2 KiB
TypeScript
// TypeScript implementation of https://github.com/Aclios/pyswizzle/blob/main/src/pyswizzle/pyswizzle.py
|
|
type Grid = Uint8Array[][];
|
|
|
|
export class BytesDeswizzle {
|
|
private data: Uint8Array;
|
|
private deswizzleDataList: [number, 0 | 1][];
|
|
private readSize: number;
|
|
private readPerTileCount: number;
|
|
private tileCount: number;
|
|
private tilePerWidth: number;
|
|
private dataReadIdx: number;
|
|
|
|
constructor(data: Uint8Array, imSize: [number, number], blockSize: [number, number], bytesPerBlock: number, swizzleMode: number) {
|
|
this.data = data;
|
|
const datasize = data.length;
|
|
const [imWidth, imHeight] = imSize;
|
|
const [blockWidth, blockHeight] = blockSize;
|
|
|
|
const expectedDataSize = Math.floor((imWidth * imHeight) / (blockWidth * blockHeight)) * bytesPerBlock;
|
|
|
|
if (expectedDataSize !== datasize)
|
|
throw new Error(
|
|
`Error: Invalid data size.\nExpected datasize (according to image and format specifications): ${expectedDataSize}\nActual datasize: ${datasize}`,
|
|
);
|
|
|
|
const tileDatasize = 512 * 2 ** swizzleMode;
|
|
const tileWidth = Math.floor(64 / bytesPerBlock) * blockWidth;
|
|
const tileHeight = 8 * blockHeight * 2 ** swizzleMode;
|
|
this.deswizzleDataList = [
|
|
[2, 0],
|
|
[2, 1],
|
|
[4, 0],
|
|
[2, 1],
|
|
[2 ** swizzleMode, 0],
|
|
];
|
|
this.readSize = 16;
|
|
this.readPerTileCount = 32 * 2 ** swizzleMode;
|
|
|
|
if (datasize % tileDatasize !== 0)
|
|
throw new Error(
|
|
`Error: Invalid data size. The data size should be a multiple of ${tileDatasize}, while the given datasize is ${datasize}. Height and/or width padding may be required in the original image.`,
|
|
);
|
|
|
|
this.tileCount = Math.floor(datasize / tileDatasize);
|
|
|
|
if (imWidth % tileWidth !== 0)
|
|
throw new Error(`Error: with the current parameters, image width should be a multiple of ${tileWidth}, but the given width is ${imWidth}`);
|
|
if (imHeight % tileHeight !== 0)
|
|
throw new Error(`Error: with the current parameters, image height should be a multiple of ${tileHeight}, but the given height is ${imHeight}`);
|
|
|
|
this.tilePerWidth = Math.floor(imWidth / tileWidth);
|
|
this.dataReadIdx = 0;
|
|
}
|
|
|
|
private getTileData(): Grid[] {
|
|
const arrayList: Grid[] = [];
|
|
for (let i = 0; i < this.readPerTileCount; i++) {
|
|
arrayList.push([[this.data.slice(this.dataReadIdx, this.dataReadIdx + this.readSize)]]);
|
|
this.dataReadIdx += this.readSize;
|
|
}
|
|
return arrayList;
|
|
}
|
|
|
|
private concatArrays(arrayList: Grid[], sectionNumber: number, axis: 0 | 1): Grid[] {
|
|
const newArrayList: Grid[] = [];
|
|
let idx = 0;
|
|
|
|
for (let i = 0; i < Math.floor(arrayList.length / sectionNumber); i++) {
|
|
const slice = arrayList.slice(idx, idx + sectionNumber);
|
|
let newGrid: Grid;
|
|
|
|
if (axis === 0) {
|
|
// np.concatenate(..., axis=0)
|
|
newGrid = [];
|
|
for (const grid of slice) {
|
|
newGrid.push(...grid);
|
|
}
|
|
} else {
|
|
// np.concatenate(..., axis=1)
|
|
newGrid = [];
|
|
for (let r = 0; r < slice[0].length; r++) {
|
|
const newRow: Uint8Array[] = [];
|
|
for (const grid of slice) {
|
|
newRow.push(...grid[r]);
|
|
}
|
|
newGrid.push(newRow);
|
|
}
|
|
}
|
|
|
|
newArrayList.push(newGrid);
|
|
idx += sectionNumber;
|
|
}
|
|
|
|
return newArrayList;
|
|
}
|
|
|
|
private deswizzleTile(): Grid {
|
|
let arrayList = this.getTileData();
|
|
for (const deswizzleData of this.deswizzleDataList) {
|
|
arrayList = this.concatArrays(arrayList, deswizzleData[0], deswizzleData[1]);
|
|
}
|
|
return arrayList[0];
|
|
}
|
|
|
|
public deswizzle(): Uint8Array {
|
|
const tileList: Grid[] = [];
|
|
for (let i = 0; i < this.tileCount; i++) {
|
|
tileList.push(this.deswizzleTile());
|
|
}
|
|
|
|
const tileListWidthConcat = this.concatArrays(tileList, this.tilePerWidth, 1);
|
|
const deswizzledGrid = this.concatArrays(tileListWidthConcat, tileListWidthConcat.length, 0)[0];
|
|
|
|
// tobytes()
|
|
const deswizzledData = new Uint8Array(this.data.length);
|
|
let offset = 0;
|
|
|
|
for (const row of deswizzledGrid) {
|
|
for (const chunk of row) {
|
|
deswizzledData.set(chunk, offset);
|
|
offset += chunk.length;
|
|
}
|
|
}
|
|
|
|
if (deswizzledData.length !== this.data.length) {
|
|
throw new Error(
|
|
`An unknown error occurred while deswizzling bytes: output data length is (somehow) different than input data length. Input data: ${this.data.length}, Output data: ${deswizzledData.length}`,
|
|
);
|
|
}
|
|
|
|
return deswizzledData;
|
|
}
|
|
}
|