Skip to content

Instantly share code, notes, and snippets.

@jurca
Last active October 24, 2022 10:44
Show Gist options
  • Save jurca/383bbf8d3140921366aca58df70b2487 to your computer and use it in GitHub Desktop.
Save jurca/383bbf8d3140921366aca58df70b2487 to your computer and use it in GitHub Desktop.
Low-bit-depth image convertor
/*
* Usage example:
* Open an image in a new tab, open the Dev tools, run the code in this gist using the console.
* After that, to create low-fi version of the opened image, run the following code:
*
* img = document.querySelector('img')
*
* document.body.append(createLoFiImage(img, [5, 6, 5])) // High color 16-bit
* document.body.append(createLoFiImage(img, [5, 5, 5])) // High color 15-bit
* document.body.append(createLoFiImage(img, [4, 4, 4])) // 12-bit
* document.body.append(createLoFiImage(img, [3, 3, 2])) // // 8-bit "truecolor" - 3 red bits, 3 green bits, 2 blue bits
* // Web-safe colors, see https://en.wikipedia.org/wiki/Web_colors#Web-safe_colors
* document.body.append(scaleImagePixelsRangeResolution(img, [6, 6, 6, 2])) // 6 values per channel + 1 bit (2 values) alpha
* document.body.append(scaleImagePixelsRangeResolution(img, [5, 5, 5, 2])) // 5 values per channel + 1 bit (2 values) alpha
* document.body.append(scaleImagePixelsRangeResolution(img, [4, 4, 4, 2])) // 4 values per channel + 1 bit (2 values) alpha
*/
function createLoFiImage(sourceImage, bitDepths) {
const bitMasks = bitDepths.map(depth => 1 << depth).concat(256)
return scaleImagePixelsRangeResolution(sourceImage, bitMasks)
}
function scaleImagePixelsRangeResolution(sourceImage, channelRange) {
const canvas = document.createElement('canvas')
canvas.width = sourceImage.naturalWidth
canvas.height = sourceImage.naturalHeight
const ctx = canvas.getContext('2d')
ctx.drawImage(sourceImage, 0, 0)
const pixels = ctx.getImageData(0, 0, canvas.width, canvas.height)
for (let i = 0; i < pixels.data.length; i++) {
const maxChannelValue = channelRange[i % 4] - 1
const pixelValue = Math.round(pixels.data[i] / 255 * maxChannelValue)
pixels.data[i] = Math.round(pixelValue / maxChannelValue * 255)
}
ctx.putImageData(pixels, 0, 0)
return canvas
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment