texture-compressor
Advanced tools
Comparing version 0.1.3 to 0.1.7
@@ -9,2 +9,3 @@ // Native | ||
const jimp = require('jimp'); | ||
const Promise = require('bluebird'); | ||
@@ -42,2 +43,11 @@ // Arguments | ||
// ASTC using Astcenc is unique in the way that it doesn't support KTX | ||
// Astcenc automatically flips the image during processing which has to be accounted for | ||
// When the -flipy flag is passed no preliminary flipping | ||
// of the image is done in order to get the inverse result | ||
// Jimp reads the original file, flips it, Astcenc encodes it and writes it to the filesystem | ||
// The file is read back as a buffer followed by a manual KTX container construction from the buffer | ||
// The result is finally saved to the filesystem | ||
function processAndReturnAsBuffer(toolPath, toolFlags = [], outputPath) { | ||
@@ -49,80 +59,83 @@ return createProcess(toolPath, toolFlags) | ||
function runCompression(image) { | ||
// Bitrate flag (2.0 bbp = 8x8 blocksize) | ||
const bitrateFlag = convertNumberToDecimalString(bitrate); | ||
const blockSizes = ['4x4', '5x4', '5x5', '6x5', '6x6', '8x5', '8x6', '8x8', '10x5', '10x6', '10x8', '10x10', '12x10', '12x12']; | ||
return new Promise((resolve, reject) => { | ||
// Bitrate flag (2.0 bbp = 8x8 blocksize) | ||
const bitrateFlag = convertNumberToDecimalString(bitrate); | ||
const blockSizes = ['4x4', '5x4', '5x5', '6x5', '6x6', '8x5', '8x6', '8x8', '10x5', '10x6', '10x8', '10x10', '12x10', '12x12']; | ||
// Quality flag | ||
const qualityOptions = ['-veryfast', '-fast', '-medium', '-thorough', '-exhaustive']; | ||
const qualityPicker = (Math.floor(quality / 2.1)); | ||
const qualityFlag = qualityOptions[qualityPicker]; // One of the five options | ||
// Quality flag | ||
const qualityOptions = ['-veryfast', '-fast', '-medium', '-thorough', '-exhaustive']; | ||
const qualityPicker = (Math.floor(quality / 2.1)); | ||
const qualityFlag = qualityOptions[qualityPicker]; // One of the five options | ||
// Flag mapping | ||
const flagMapping = [ | ||
'-cl', image, // Encode with LDR-linear submode | ||
output, | ||
`${bitrateFlag}`, | ||
'-j', os.cpus().length, | ||
`${qualityFlag}`, | ||
]; | ||
// Flag mapping | ||
const flagMapping = [ | ||
'-cl', image, // Encode with LDR-linear submode | ||
output, | ||
`${bitrateFlag}`, | ||
'-j', os.cpus().length, | ||
`${qualityFlag}`, | ||
]; | ||
// Transparent mapping, tool doesn't accept empty flags | ||
if (transparent) { | ||
flagMapping.push('-alphablend'); | ||
} | ||
// Transparent mapping, tool doesn't accept empty flags | ||
if (transparent) { | ||
flagMapping.push('-alphablend'); | ||
} | ||
const toolPath = path.join(compressionToolDirectory, 'astcenc'); | ||
const toolFlags = flags ? splitFlagAndValue(createFlagsForTool(flags)) : []; | ||
const toolPath = path.join(compressionToolDirectory, 'astcenc'); | ||
const toolFlags = flags ? splitFlagAndValue(createFlagsForTool(flags)) : []; | ||
const combinedFlags = [...flagMapping, ...toolFlags]; | ||
const combinedFlags = [...flagMapping, ...toolFlags]; | ||
// Astcenc does not support writing to KTX by directly so we prepend it with a KTX header | ||
processAndReturnAsBuffer(toolPath, combinedFlags, output) | ||
.then((buffer) => { | ||
// https://github.com/AnalyticalGraphicsInc/gltf-pipeline/blob/a28152503f28be88051de8df85f5f6a350169e8b/lib/compressTexture.js#L436-L485 | ||
const blockWidth = buffer.readUInt8(4); | ||
const blockHeight = buffer.readUInt8(5); | ||
const xsize = [buffer.readUInt8(7), buffer.readUInt8(8), buffer.readUInt8(9)]; | ||
const ysize = [buffer.readUInt8(10), buffer.readUInt8(11), buffer.readUInt8(12)]; | ||
const pixelHeight = xsize[0] + 256 * xsize[1] + 65536 * xsize[2]; | ||
const pixelWidth = ysize[0] + 256 * ysize[1] + 65536 * ysize[2]; | ||
const blockSize = `${blockWidth}x${blockHeight}`; | ||
const glInternalFormat = 0x93B0 + blockSizes.indexOf(blockSize); | ||
const glBaseInternalFormat = 0x1908; // gl.RGBA | ||
const imageData = buffer.slice(16); | ||
const imageSize = imageData.length; | ||
// Astcenc does not support writing to KTX by directly so we prepend it with a KTX header | ||
processAndReturnAsBuffer(toolPath, combinedFlags, output) | ||
.then((buffer) => { | ||
// https://github.com/AnalyticalGraphicsInc/gltf-pipeline/blob/a28152503f28be88051de8df85f5f6a350169e8b/lib/compressTexture.js#L436-L485 | ||
const blockWidth = buffer.readUInt8(4); | ||
const blockHeight = buffer.readUInt8(5); | ||
const xsize = [buffer.readUInt8(7), buffer.readUInt8(8), buffer.readUInt8(9)]; | ||
const ysize = [buffer.readUInt8(10), buffer.readUInt8(11), buffer.readUInt8(12)]; | ||
const pixelHeight = xsize[0] + 256 * xsize[1] + 65536 * xsize[2]; | ||
const pixelWidth = ysize[0] + 256 * ysize[1] + 65536 * ysize[2]; | ||
const blockSize = `${blockWidth}x${blockHeight}`; | ||
const glInternalFormat = 0x93B0 + blockSizes.indexOf(blockSize); | ||
const glBaseInternalFormat = 0x1908; // gl.RGBA | ||
const imageData = buffer.slice(16); | ||
const imageSize = imageData.length; | ||
// KTX header | ||
const ktxHeader = Buffer.allocUnsafe(68); | ||
const identifier = [0xAB, 0x4B, 0x54, 0x58, 0x20, 0x31, 0x31, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A]; | ||
// KTX header | ||
const ktxHeader = Buffer.allocUnsafe(68); | ||
const identifier = [0xAB, 0x4B, 0x54, 0x58, 0x20, 0x31, 0x31, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A]; | ||
for (let i = 0; i < 12; i++) { | ||
ktxHeader.writeUInt8(identifier[i], i); | ||
} | ||
for (let i = 0; i < 12; i++) { | ||
ktxHeader.writeUInt8(identifier[i], i); | ||
} | ||
ktxHeader.writeUInt32LE(0x04030201, 12); // endianness | ||
ktxHeader.writeUInt32LE(0, 16); // glType | ||
ktxHeader.writeUInt32LE(1, 20); // glTypeSize | ||
ktxHeader.writeUInt32LE(0, 24); // glFormat | ||
ktxHeader.writeUInt32LE(glInternalFormat, 28); // glInternalFormat | ||
ktxHeader.writeUInt32LE(glBaseInternalFormat, 32); // glBaseInternalFormat | ||
ktxHeader.writeUInt32LE(pixelWidth, 36); // pixelWidth | ||
ktxHeader.writeUInt32LE(pixelHeight, 40); // pixelHeight | ||
ktxHeader.writeUInt32LE(0, 44); // pixelDepth | ||
ktxHeader.writeUInt32LE(0, 48); // numberOfArrayElements | ||
ktxHeader.writeUInt32LE(1, 52); // numberOfFaces | ||
ktxHeader.writeUInt32LE(1, 56); // numberOfMipmapLevels | ||
ktxHeader.writeUInt32LE(0, 60); // bytesOfKeyValueData | ||
ktxHeader.writeUInt32LE(imageSize, 64); // imageSize | ||
ktxHeader.writeUInt32LE(0x04030201, 12); // endianness | ||
ktxHeader.writeUInt32LE(0, 16); // glType | ||
ktxHeader.writeUInt32LE(1, 20); // glTypeSize | ||
ktxHeader.writeUInt32LE(0, 24); // glFormat | ||
ktxHeader.writeUInt32LE(glInternalFormat, 28); // glInternalFormat | ||
ktxHeader.writeUInt32LE(glBaseInternalFormat, 32); // glBaseInternalFormat | ||
ktxHeader.writeUInt32LE(pixelWidth, 36); // pixelWidth | ||
ktxHeader.writeUInt32LE(pixelHeight, 40); // pixelHeight | ||
ktxHeader.writeUInt32LE(0, 44); // pixelDepth | ||
ktxHeader.writeUInt32LE(0, 48); // numberOfArrayElements | ||
ktxHeader.writeUInt32LE(1, 52); // numberOfFaces | ||
ktxHeader.writeUInt32LE(1, 56); // numberOfMipmapLevels | ||
ktxHeader.writeUInt32LE(0, 60); // bytesOfKeyValueData | ||
ktxHeader.writeUInt32LE(imageSize, 64); // imageSize | ||
console.log(blockSize, imageSize); | ||
const result = Buffer.concat([ktxHeader, imageData]); | ||
console.log(blockSize, imageSize); | ||
const result = Buffer.concat([ktxHeader, imageData]); | ||
fs.writeFile(output, result, 'binary', (error) => { | ||
if (error) { | ||
console.error(error); | ||
} else { | ||
console.log(`Succesfully written file to ${output}`); | ||
} | ||
fs.writeFile(output, result, 'binary', (error) => { | ||
if (error) { | ||
reject(console.error(error)); | ||
} else { | ||
resolve(); | ||
console.log(`Succesfully written file to ${output}`); | ||
} | ||
}); | ||
}); | ||
}); | ||
}); | ||
} | ||
@@ -167,8 +180,15 @@ | ||
} else { | ||
// Compress flipped instead of the direct input | ||
runCompression(`${tempDirectory}/${tempFilename}`); | ||
// Clean up the temporary directory and the temporary image | ||
fsExtra.remove(`${tempDirectory}/${tempFilename}`); | ||
fsExtra.remove(tempDirectory); | ||
// Check if the file exists | ||
fsExtra.exists(`${tempDirectory}/${tempFilename}`, (exists) => { | ||
if (exists) { | ||
// Compress flipped instead of the direct input | ||
runCompression(`${tempDirectory}/${tempFilename}`) | ||
// Ensure final file has been written before removing the temporary file (this may be unnecessary) | ||
.then(() => { | ||
// Clean up the temporary directory and the temporary image | ||
fsExtra.remove(`${tempDirectory}/${tempFilename}`); | ||
fsExtra.remove(tempDirectory); | ||
}); | ||
} | ||
}); | ||
} | ||
@@ -175,0 +195,0 @@ }); |
@@ -0,3 +1,5 @@ | ||
// Native | ||
const { spawn } = require('child_process'); | ||
// Vendor | ||
const { spawn } = require('child_process'); | ||
const Promise = require('bluebird'); | ||
@@ -4,0 +6,0 @@ |
{ | ||
"name": "texture-compressor", | ||
"version": "0.1.3", | ||
"version": "0.1.7", | ||
"description": "CLI tool for texture compression using ASTC, ETC, PVRTC and S3TC in a KTX container.", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
36035381
3068