How to get image color mode (CMYK, RGB …) in Javascript

て烟熏妆下的殇ゞ 提交于 2021-02-19 08:12:49

问题


can the JavaScript check the color mode of a image?

I did a lot of search about this but the only thing I saw was color mode convert (but the convert wants you to set the original color mode)


I add this: --allow-file-access-from-files to have a full control of img in canvas beacause I am using GoogleChrome

Html

<canvas id="canvas" width=6000 height=7919></canvas>

Js

var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");

var img = new Image();
img.crossOrigin = "anonymous";
img.onload = start;
img.src = "file:///D:/vincent-van-gogh-the-starry-night-picture-157544-2.png";

回答1:


Yes - basically JavaScript is able to determine the color mode of a png, but therefore it would be required to 1. convert png to base64 2. convert base64 to byte array 3. reading / parsing the array regarding png specification

A possible approach could look like this:

var PNG = {

        parse: function(imgTag) {
            var base64 = PNG.asBase64(imgTag);
            var byteData = PNG.utils.base64StringToByteArray(base64);
            var parsedPngData = PNG.utils.parseBytes(byteData);

            return PNG.utils.enrichParsedData(parsedPngData);
        },

        asBase64: function(imgTag) {
            var canvas = document.createElement("canvas");
            canvas.width = imgTag.width; 
            canvas.height = imgTag.height; 
            var ctx = canvas.getContext("2d"); 
            ctx.drawImage(imgTag, 0, 0); 
            var dataURL = canvas.toDataURL("image/png");
            return dataURL.split('base64,')[1];
        },

        utils: {
            base64StringToByteArray: function(base64String) {
                //http://stackoverflow.com/questions/16245767/creating-a-blob-from-a-base64-string-in-javascript
                var byteCharacters = atob(base64String);
                var byteNumbers = new Array(byteCharacters.length);
                for (var i = 0; i < byteCharacters.length; i++) {
                    byteNumbers[i] = byteCharacters.charCodeAt(i);
                }
                return new Uint8Array(byteNumbers);
            },

            parseBytes: function(bytes) {
                var pngData = {};
                //see https://en.wikipedia.org/wiki/Portable_Network_Graphics

                //verify file header
                pngData['headerIsValid'] = bytes[0] == 0x89
                            && bytes[1] == 0x50
                            && bytes[2] == 0x4E
                            && bytes[3] == 0x47
                            && bytes[4] == 0x0D
                            && bytes[5] == 0x0A
                            && bytes[6] == 0x1A
                            && bytes[7] == 0x0A

                if (!pngData.headerIsValid) {
                    console.warn('Provided data does not belong to a png');
                    return pngData;
                }

                //parsing chunks
                var chunks = [];

                var chunk = PNG.utils.parseChunk(bytes, 8);
                chunks.push(chunk);

                while (chunk.name !== 'IEND') {
                    chunk = PNG.utils.parseChunk(bytes, chunk.end);
                    chunks.push(chunk);
                }

                pngData['chunks'] = chunks;
                return pngData;
            },

            parseChunk: function(bytes, start) {
                var chunkLength = PNG.utils.bytes2Int(bytes.slice(start, start + 4));

                var chunkName = '';
                chunkName += String.fromCharCode(bytes[start + 4]);
                chunkName += String.fromCharCode(bytes[start + 5]);
                chunkName += String.fromCharCode(bytes[start + 6]);
                chunkName += String.fromCharCode(bytes[start + 7]);

                var chunkData = [];
                for (var idx = start + 8; idx<chunkLength + start + 8; idx++) {
                    chunkData.push(bytes[idx]);
                }

                //TODO validate crc as required!

                return {
                    start: start,
                    end: Number(start) + Number(chunkLength) + 12, //12 = 4 (length) + 4 (name) + 4 (crc)
                    length: chunkLength,
                    name: chunkName,
                    data: chunkData,
                    crc: [
                        bytes[chunkLength + start + 8],
                        bytes[chunkLength + start + 9],
                        bytes[chunkLength + start + 10],
                        bytes[chunkLength + start + 11]
                    ],
                    crcChecked: false
                };
            },

            enrichParsedData: function(pngData) {
                var idhrChunk = PNG.utils.getChunk(pngData, 'IDHR');

                //see http://www.libpng.org/pub/png/spec/1.2/PNG-Chunks.html
                pngData.width = PNG.utils.bytes2Int(idhrChunk.data.slice(0, 4));
                pngData.height = PNG.utils.bytes2Int(idhrChunk.data.slice(4, 8));
                pngData.bitDepth = PNG.utils.bytes2Int(idhrChunk.data.slice(8, 9));
                pngData.colorType = PNG.utils.bytes2Int(idhrChunk.data.slice(9, 10));
                pngData.compressionMethod = PNG.utils.bytes2Int(idhrChunk.data.slice(10, 11));
                pngData.filterMethod = PNG.utils.bytes2Int(idhrChunk.data.slice(11, 12));
                pngData.interlaceMethod = PNG.utils.bytes2Int(idhrChunk.data.slice(12, 13));

                pngData.isGreyScale = pngData.colorType == 0 || pngData.colorType == 4;
                pngData.isRgb = pngData.colorType == 2 || pngData.colorType == 6;
                pngData.hasAlpha = pngData.colorType == 4 || pngData.colorType == 6;
                pngData.hasPaletteMode = pngData.colorType == 3 && PNG.utils.getChunk(pngData, 'PLTE') != null;

                return pngData;
            },

            getChunks: function(pngData, chunkName) {
                var chunksForName = [];
                for (var idx = 0; idx<pngData.chunks.length; idx++) {
                    if (pngData.chunks[idx].name = chunkName) {
                        chunksForName.push(pngData.chunks[idx]);
                    }
                }
                return chunksForName;
            },

            getChunk: function(pngData, chunkName) {
                for (var idx = 0; idx<pngData.chunks.length; idx++) {
                    if (pngData.chunks[idx].name = chunkName) {
                        return pngData.chunks[idx];
                    }
                }
                return null;
            },

            bytes2Int: function(bytes) {
                var ret = 0;

                for (var idx = 0; idx<bytes.length; idx++) {
                    ret += bytes[idx];
                    if (idx < bytes.length - 1) {
                        ret = ret << 8;
                    }
                }

                return ret;
            }
        }
    }

Which could be used as follows:

var pngData = PNG.parse(document.getElementById('yourImageId'));
console.log(pngData);

It contains some information, like color mode, number of chunks, the chunks itself, bit depth, etc.

Hope it helps.




回答2:


Can the JavaScript check the color mode of a image?

Yes and no.

No if you use ordinary image loading. All images that are supported by the browser are converted to RGB(A) before they are handed to us through the Image object (HTMLImageElement).

At this point no information about the original format and color model is presented except from its size and origin.

Canvas only deals with RGBA as all other elements that are displayed and there exist no native method to address color models such as CMYK.

You could always read the RGBA values and convert to CMYK naively, however, without a ICC profile for the target printer you would run into all sort of problems due to the wider gamut of RGB, and printer as well as print medium characteristics which must be adjusted for through ICC profiles. Meaning the result will not produce correct colors in most cases.

You would have to have a server-side solution setup for this to work. Send image to server, convert to CMYK/apply ICC, then send to printer. ImageMagick could be one way to go about it. The browser is simply not cut (nor intended) for print oriented processing.

Yes if you're willing to write image parser manually as well as ICC parser. You would need to support a variety of formats and format combinations, and also be able to apply ICC/gamma on import as well as export to CMYK through the target ICC (meaning you need to support XYZ/LAB color spaces).

The export would require you to write a file writer supporting the CMYK color space and ICC embedding.

The maturing process, bugs, instabilities etc. would be a natural part of the process and likely not something you would want to use in production right away.

If you're just after the color mode of the file and can load the image like ordinary you can of course load the file first through XHR, then scan the file using typed array to locate the information describing the color format depending on format. Then pass the typed array as Blob -> object-URL to load as an image, go through canvas and convert each pixel to CMYK values.

But from this point you will have the same problems as described above and would not escape writing the file writer etc.




回答3:


You can use exifreader package to read image metadata.

import ExifReader from 'exifreader'

const reader = new FileReader()

reader.onload = (event) => {
  const metadata = ExifReader.load(event.target.result, { expanded: true })
  const { file: { 'Color Components': { value } } } = metadata

  switch (value) {
  case 3: console.log('RGB'); break
  case 4: console.log('CMYK'); break
  default: console.log('Unknown')
  }
}

reader.readAsArrayBuffer(instaceOfFileObject)

It doesn't have to be File object, but the ExifReader.load() expects array buffer as its first arg.

Reference: https://www.get-metadata.com/file-info/color-components



来源:https://stackoverflow.com/questions/37992117/how-to-get-image-color-mode-cmyk-rgb-in-javascript

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!