UNPKG

pw-guild-icon-parser

Version:

Parser for Perfect World guild icon lists - converts PNG icons to DDS atlas format with DXT5 compression

98 lines 3.1 kB
import { writeFile } from 'fs/promises'; import { compressDXT5 } from './dxt5.js'; const DDS_MAGIC = 0x20534444; // "DDS " export async function writeDDS(ddsPath, width, height, rgbaData) { // Compress to DXT5 const compressedData = compressDXT5(width, height, rgbaData); // Validate compressed data size const blockWidth = Math.ceil(width / 4); const blockHeight = Math.ceil(height / 4); const expectedSize = blockWidth * blockHeight * 16; // 16 bytes per DXT5 block if (compressedData.length !== expectedSize) { throw new Error(`Invalid compressed data size: expected ${expectedSize}, got ${compressedData.length}`); } // Ensure linearSize fits in uint32 const linearSize = compressedData.length; if (linearSize < 0 || linearSize > 0xFFFFFFFF) { throw new Error(`Linear size out of range: ${linearSize}`); } // Create DDS header const header = createDDSHeader(width, height, linearSize); // Combine header and compressed data const ddsFile = Buffer.concat([header, compressedData]); await writeFile(ddsPath, ddsFile); } function createDDSHeader(width, height, linearSize) { const header = Buffer.alloc(128); let offset = 0; // Magic number header.writeUInt32LE(DDS_MAGIC, offset); offset += 4; // DDS_HEADER size header.writeUInt32LE(124, offset); offset += 4; // Flags: DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT | DDSD_LINEARSIZE header.writeUInt32LE(0x1 | 0x2 | 0x4 | 0x8 | 0x80000, offset); offset += 4; // Height header.writeUInt32LE(height, offset); offset += 4; // Width header.writeUInt32LE(width, offset); offset += 4; // PitchOrLinearSize header.writeUInt32LE(linearSize, offset); offset += 4; // Depth header.writeUInt32LE(0, offset); offset += 4; // MipMapCount header.writeUInt32LE(1, offset); offset += 4; // Reserved (11 integers = 44 bytes) offset += 44; // DDS_PIXELFORMAT // Size header.writeUInt32LE(32, offset); offset += 4; // Flags: DDPF_FOURCC header.writeUInt32LE(0x4, offset); offset += 4; // FourCC: "DXT5" (4 bytes ASCII) const fourCC = Buffer.from('DXT5', 'ascii'); fourCC.copy(header, offset, 0, 4); offset += 4; // RGBBitCount header.writeUInt32LE(0, offset); offset += 4; // RBitMask header.writeUInt32LE(0, offset); offset += 4; // GBitMask header.writeUInt32LE(0, offset); offset += 4; // BBitMask header.writeUInt32LE(0, offset); offset += 4; // ABitMask header.writeUInt32LE(0, offset); offset += 4; // DDS_HEADER continued // Caps header.writeUInt32LE(0x1000, offset); // DDSCAPS_TEXTURE offset += 4; // Caps2 header.writeUInt32LE(0, offset); offset += 4; // Caps3 header.writeUInt32LE(0, offset); offset += 4; // Caps4 header.writeUInt32LE(0, offset); offset += 4; // Reserved2 header.writeUInt32LE(0, offset); offset += 4; return header; } //# sourceMappingURL=writer.js.map