{"record":{"id":"421b2b92dc1cecaf","repo":"gchq/CyberChef","slug":"error-normalising-image-err","errorCode":null,"errorMessage":"Error normalising image. (${err})","messagePattern":"Error normalising image\\. \\((.+?)\\)","errorType":"exception","errorClass":"OperationError","httpStatus":null,"severity":"warning","filePath":"src/core/lib/QRCode.mjs","lineNumber":36,"sourceCode":" * @param {ArrayBuffer} input\n * @param {boolean} normalise\n * @returns {string}\n */\nexport async function parseQrCode(input, normalise) {\n    let image;\n    try {\n        image = await Jimp.read(input);\n    } catch (err) {\n        throw new OperationError(`Error opening image. (${err})`);\n    }\n\n    try {\n        if (normalise) {\n            image.greyscale();\n            image.normalize();\n        }\n    } catch (err) {\n        throw new OperationError(`Error normalising image. (${err})`);\n    }\n\n    // Remove transparency which jsQR cannot handle\n    image.scan((x, y, idx) => {\n        // If pixel is fully transparent, make it opaque white\n        if (image.bitmap.data[idx + 3] === 0x00) {\n            image.bitmap.data[idx + 0] = 0xff;\n            image.bitmap.data[idx + 1] = 0xff;\n            image.bitmap.data[idx + 2] = 0xff;\n        }\n        // Otherwise, make it fully opaque at its existing colour\n        image.bitmap.data[idx + 3] = 0xff;\n    });\n    image = await Jimp.read(await image.getBuffer(JimpMime.jpeg));\n\n    const qrData = jsQR(\n        new Uint8ClampedArray(image.bitmap.data),\n        image.width,","sourceCodeStart":18,"sourceCodeEnd":54,"githubUrl":"https://github.com/gchq/CyberChef/blob/4290ea753912378913b1f3f54e0fc5720afeda5d/src/core/lib/QRCode.mjs#L18-L54","documentation":"Thrown by parseQrCode when `image.greyscale()` or `image.normalize()` throws after a successful read. The original Jimp error is appended. This is rare and typically indicates an edge case in the decoded bitmap (e.g. unsupported colour space or zero-pixel image).","triggerScenarios":"Calling parseQrCode(input, true) where the image decodes but Jimp's pixel operations fail — degenerate dimensions (0x0), unusual bit depth, or a Jimp version regression.","commonSituations":"Passing normalise=true with an image Jimp decoded only partially; Jimp/library version mismatch after upgrade; CMYK/16-bit images that Jimp represents oddly.","solutions":["Retry with normalise=false to bypass greyscale/normalise.","Re-encode the source image to a standard 8-bit sRGB PNG before parsing.","Check the Jimp version is compatible with this CyberChef build."],"exampleFix":"// before\nawait parseQrCode(input, true); // throws on degenerate image\n// after\nawait parseQrCode(input, false);","handlingStrategy":"retry","validationCode":"async function safeParseQr(input) {\n  try { return await parseQrCode(input, true); }\n  catch (e) { if (/normalising/.test(e.message)) return await parseQrCode(input, false); throw e; }\n}","typeGuard":null,"tryCatchPattern":"try {\n  return await parseQrCode(input, true);\n} catch (e) {\n  if (e instanceof OperationError && /normalising/.test(e.message)) {\n    return await parseQrCode(input, false); // retry without normalise\n  }\n  throw e;\n}","preventionTips":["Default to normalise=false for unusual/16-bit images.","Re-encode sources to 8-bit sRGB PNG first.","Keep Jimp version aligned with the CyberChef build."],"tags":["qrcode","image","jimp","normalise"],"backgroundTag":null,"analyzedSha":"4290ea753912378913b1f3f54e0fc5720afeda5d","analyzedAt":"2026-08-13T06:05:50.210Z","schemaVersion":2},"datasetVersion":"2026-08-13T09:17:06.757Z"}