UNPKG

pw-guild-icon-parser

Version:

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

47 lines 2.18 kB
import { open } from 'fs/promises'; import { compressDXT5Block } from './dxt5.js'; /** * Patch a DDS file by updating only the blocks for a specific icon * This is MUCH faster than decompressing/recompressing the entire atlas */ export async function patchDDSIcon(ddsPath, iconRgbaData, iconWidth, iconHeight, position, atlasWidth) { // Calculate block positions const blockWidth = Math.ceil(atlasWidth / 4); // Position in pixels const pixelX = position.col * iconWidth; const pixelY = position.row * iconHeight; // Position in blocks (DXT5 uses 4x4 pixel blocks) const startBlockX = Math.floor(pixelX / 4); const startBlockY = Math.floor(pixelY / 4); // Number of blocks for this icon (16x16 = 4x4 blocks) const iconBlocksX = Math.ceil(iconWidth / 4); const iconBlocksY = Math.ceil(iconHeight / 4); // DDS header is 128 bytes, then compressed data starts const headerSize = 128; const blockSize = 16; // DXT5 block is 16 bytes (4x4 pixels) // Open file for random access const fileHandle = await open(ddsPath, 'r+'); try { for (let blockY = 0; blockY < iconBlocksY; blockY++) { for (let blockX = 0; blockX < iconBlocksX; blockX++) { // Calculate pixel position in the icon const iconPixelX = blockX * 4; const iconPixelY = blockY * 4; const iconOffset = (iconPixelY * iconWidth + iconPixelX) * 4; // Compress this 4x4 block const compressedBlock = compressDXT5Block(iconRgbaData, iconOffset, iconWidth); // Calculate position in the DDS file const atlasBlockX = startBlockX + blockX; const atlasBlockY = startBlockY + blockY; const blockIndex = atlasBlockY * blockWidth + atlasBlockX; const fileOffset = headerSize + (blockIndex * blockSize); // Write the compressed block directly to file await fileHandle.write(compressedBlock, 0, blockSize, fileOffset); } } } finally { await fileHandle.close(); } } //# sourceMappingURL=patcher.js.map