decode-ico
Advanced tools
Comparing version 0.1.6 to 0.2.0
93
index.js
@@ -0,1 +1,3 @@ | ||
const toDataView = require('to-data-view') | ||
function makeDivisibleByFour (input) { | ||
@@ -49,18 +51,9 @@ const rest = input % 4 | ||
function isPng (data, offset) { | ||
return ( | ||
data[offset + 0] === 137 && | ||
data[offset + 1] === 80 && | ||
data[offset + 2] === 78 && | ||
data[offset + 3] === 71 && | ||
data[offset + 4] === 13 && | ||
data[offset + 5] === 10 && | ||
data[offset + 6] === 26 && | ||
data[offset + 7] === 10 | ||
) | ||
function isPng (view, offset) { | ||
return (view.getUint32(offset + 0) === 0x89504e47 && view.getUint32(offset + 4) === 0x0d0a1a0a) | ||
} | ||
function pngBitsPerPixel (data, offset) { | ||
const bitDepth = data[offset + 24] | ||
const colorType = data[offset + 25] | ||
function pngBitsPerPixel (view, offset) { | ||
const bitDepth = view.getUint8(offset + 24) | ||
const colorType = view.getUint8(offset + 25) | ||
@@ -76,11 +69,11 @@ if (colorType === 0) return bitDepth * 1 | ||
function pngWidth (data, offset) { | ||
return data.readUInt32BE(offset + 16) | ||
function pngWidth (view, offset) { | ||
return view.getUint32(offset + 16, false) | ||
} | ||
function pngHeight (data, offset) { | ||
return data.readUInt32BE(offset + 20) | ||
function pngHeight (view, offset) { | ||
return view.getUint32(offset + 20, false) | ||
} | ||
function decodeTrueColorBmp (data, offset, { width, height, colorDepth }) { | ||
function decodeTrueColorBmp (data, { width, height, colorDepth }) { | ||
if (colorDepth !== 32 && colorDepth !== 24) { | ||
@@ -90,3 +83,3 @@ throw new Error(`A color depth of ${colorDepth} is not supported`) | ||
const xor = new Bitmap(data, offset, { width, height, colorDepth, format: 'BGRA' }) | ||
const xor = new Bitmap(data, 0, { width, height, colorDepth, format: 'BGRA' }) | ||
const and = (colorDepth === 24) | ||
@@ -96,3 +89,3 @@ ? new Bitmap(data, xor.offset + xor.size, { width, height, colorDepth: 1, format: 'A' }) | ||
const result = Buffer.alloc(width * height * 4) | ||
const result = new Uint8Array(width * height * 4) | ||
@@ -117,3 +110,3 @@ let idx = 0 | ||
function decodePaletteBmp (data, offset, { width, height, colorDepth, colorCount }) { | ||
function decodePaletteBmp (data, { width, height, colorDepth, colorCount }) { | ||
if (colorDepth !== 8 && colorDepth !== 4 && colorDepth !== 2 && colorDepth !== 1) { | ||
@@ -123,7 +116,7 @@ throw new Error(`A color depth of ${colorDepth} is not supported`) | ||
const colors = new Bitmap(data, offset, { width: colorCount, height: 1, colorDepth: 32, format: 'BGRA' }) | ||
const colors = new Bitmap(data, 0, { width: colorCount, height: 1, colorDepth: 32, format: 'BGRA' }) | ||
const xor = new Bitmap(data, colors.offset + colors.size, { width, height, colorDepth, format: 'C' }) | ||
const and = new Bitmap(data, xor.offset + xor.size, { width, height, colorDepth: 1, format: 'A' }) | ||
const result = Buffer.alloc(width * height * 4) | ||
const result = new Uint8Array(width * height * 4) | ||
@@ -146,7 +139,7 @@ let idx = 0 | ||
function decodeBmp ({ data, width: iconWidth, height: iconHeight }) { | ||
const headerSize = data.readUInt32LE(0) | ||
const bitmapWidth = (data.readUInt32LE(4) / 1) | 0 | ||
const bitmapHeight = (data.readUInt32LE(8) / 2) | 0 | ||
const colorDepth = data.readUInt16LE(14) | ||
let colorCount = data.readUInt32LE(32) | ||
const headerSize = data.getUint32(0, true) | ||
const bitmapWidth = (data.getUint32(4, true) / 1) | 0 | ||
const bitmapHeight = (data.getUint32(8, true) / 2) | 0 | ||
const colorDepth = data.getUint16(14, true) | ||
let colorCount = data.getUint32(32, true) | ||
@@ -160,5 +153,7 @@ if (colorCount === 0 && colorDepth <= 8) { | ||
const bitmapData = new Uint8Array(data.buffer, data.byteOffset + headerSize, data.byteLength - headerSize) | ||
const result = colorCount | ||
? decodePaletteBmp(data, headerSize, { width, height, colorDepth, colorCount }) | ||
: decodeTrueColorBmp(data, headerSize, { width, height, colorDepth }) | ||
? decodePaletteBmp(bitmapData, { width, height, colorDepth, colorCount }) | ||
: decodeTrueColorBmp(bitmapData, { width, height, colorDepth }) | ||
@@ -169,13 +164,13 @@ return { width, height, data: result, colorDepth } | ||
module.exports = function decodeIco (input) { | ||
input = Buffer.isBuffer(input) ? input : Buffer.from(input) | ||
const view = toDataView(input) | ||
if (input.byteLength < 6) { | ||
if (view.byteLength < 6) { | ||
throw new Error('Truncated header') | ||
} | ||
if (input.readUInt16LE(0, true) !== 0) { | ||
if (view.getUint16(0, true) !== 0) { | ||
throw new Error('Invalid magic bytes') | ||
} | ||
const type = input.readUInt16LE(2, true) | ||
const type = view.getUint16(2, true) | ||
@@ -186,5 +181,5 @@ if (type !== 1 && type !== 2) { | ||
const length = input.readUInt16LE(4, true) | ||
const length = view.getUint16(4, true) | ||
if (input.byteLength < 6 + (16 * length)) { | ||
if (view.byteLength < 6 + (16 * length)) { | ||
throw new Error('Truncated image list') | ||
@@ -194,24 +189,24 @@ } | ||
return Array.from({ length }, (_, idx) => { | ||
const width = input.readUInt8(6 + (16 * idx) + 0, true) | ||
const height = input.readUInt8(6 + (16 * idx) + 1, true) | ||
const size = input.readUInt32LE(6 + (16 * idx) + 8, true) | ||
const offset = input.readUInt32LE(6 + (16 * idx) + 12, true) | ||
const data = input.slice(offset, offset + size) | ||
const width = view.getUint8(6 + (16 * idx) + 0) | ||
const height = view.getUint8(6 + (16 * idx) + 1) | ||
const size = view.getUint32(6 + (16 * idx) + 8, true) | ||
const offset = view.getUint32(6 + (16 * idx) + 12, true) | ||
const hotspot = (type !== 2 ? null : { | ||
x: input.readUInt16LE(6 + (16 * idx) + 4, true), | ||
y: input.readUInt16LE(6 + (16 * idx) + 6, true) | ||
x: view.getUint16(6 + (16 * idx) + 4, true), | ||
y: view.getUint16(6 + (16 * idx) + 6, true) | ||
}) | ||
if (isPng(input, offset)) { | ||
if (isPng(view, offset)) { | ||
return { | ||
bpp: pngBitsPerPixel(input, offset), | ||
data, | ||
height: pngHeight(input, offset), | ||
bpp: pngBitsPerPixel(view, offset), | ||
data: new Uint8Array(view.buffer, view.byteOffset + offset, size), | ||
height: pngHeight(view, offset), | ||
hotspot, | ||
type: 'png', | ||
width: pngWidth(input, offset) | ||
width: pngWidth(view, offset) | ||
} | ||
} | ||
const data = new DataView(view.buffer, view.byteOffset + offset, size) | ||
const bmp = decodeBmp({ data, width, height }) | ||
@@ -218,0 +213,0 @@ |
{ | ||
"name": "decode-ico", | ||
"version": "0.1.6", | ||
"version": "0.2.0", | ||
"license": "MIT", | ||
@@ -9,2 +9,5 @@ "repository": "LinusU/decode-ico", | ||
}, | ||
"dependencies": { | ||
"to-data-view": "^1.0.0" | ||
}, | ||
"devDependencies": { | ||
@@ -11,0 +14,0 @@ "globby": "^6.1.0", |
@@ -21,6 +21,6 @@ # Decode ICO | ||
console.log(images[0]) | ||
//=> { width: 16, height: 16, type: 'bmp', data: Buffer(...), bpp: 32, hotspot: null } | ||
//=> { width: 16, height: 16, type: 'bmp', data: Uint8Array(...), bpp: 32, hotspot: null } | ||
console.log(images[1]) | ||
//=> { width: 32, height: 32, type: 'bmp', data: Buffer(...), bpp: 32, hotspot: null } | ||
//=> { width: 32, height: 32, type: 'bmp', data: Uint8Array(...), bpp: 32, hotspot: null } | ||
``` | ||
@@ -30,3 +30,3 @@ | ||
### `decodeIco(source: Buffer) => Image[]` | ||
### `decodeIco(source: ArrayBuffer | Buffer) => Image[]` | ||
@@ -40,7 +40,7 @@ Decodes the `.ico` file in the given buffer, and returns an array of images. | ||
- `type: String` - The type of image, will be one of `bmp` or `png` | ||
- `data: Buffer` - The data of the image, format depends on `type`, see below | ||
- `bpp: Number` - The color depth of the image as the number of bits used per pixel | ||
- `data: Uint8Array` - The data of the image, format depends on `type`, see below | ||
- `hotspot: null | Hotspot` - If the image is a cursor (`.cur`), this is the hotspot | ||
The format of the `data` parameter depends on the type of image. When the image is of type `bmp`, the `data` buffer will hold raw pixel data in the RGBA order, with integer values between 0 and 255 (included). When the type is `png`, the buffer will be png data. | ||
The format of the `data` parameter depends on the type of image. When the image is of type `bmp`, the `data` array will hold raw pixel data in the RGBA order, with integer values between 0 and 255 (included). When the type is `png`, the array will be png data. | ||
@@ -47,0 +47,0 @@ The `hotspot` property will either be `null`, or an object with an `x` and `y` property. |
@@ -54,3 +54,3 @@ /* eslint-env mocha */ | ||
assert.strictEqual(imageData.data.length, expected.data.length, 'The decoded data should match the target data (length)') | ||
assert.ok(Buffer.compare(imageData.data, expected.data) === 0, 'The decoded data should match the target data (bytes)') | ||
assert.ok(Buffer.compare(Buffer.from(imageData.data), expected.data) === 0, 'The decoded data should match the target data (bytes)') | ||
}) | ||
@@ -83,3 +83,3 @@ }) | ||
assert.strictEqual(imageData.data.length, expected.data.length, 'The decoded data should match the target data (length)') | ||
assert.ok(Buffer.compare(imageData.data, expected.data) === 0, 'The decoded data should match the target data (bytes)') | ||
assert.ok(Buffer.compare(Buffer.from(imageData.data), expected.data) === 0, 'The decoded data should match the target data (bytes)') | ||
}) | ||
@@ -86,0 +86,0 @@ }) |
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
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
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
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
157919
33
2072
1
+ Addedto-data-view@^1.0.0
+ Addedto-data-view@1.1.0(transitive)