Nodejs抽出イメージの主な色(二)


Nodejs抽出イメージの主な色(一)
どのように色の抽出の正確さを高めますか?
主にimagesjpeg-jspngjsによって共有され、互いに競合しない.
// node-pixels.js
'use strict';

var ndarray = require('ndarray');
// var path = require('path');
var PNG = require('pngjs').PNG; //    png   
var jpeg = require('jpeg-js'); //    jpg/jpeg   
var pack = require('ndarray-pack');
var GifReader = require('omggif').GifReader;
var Bitmap = require('node-bitmap');
var fs = require('fs');
var request = require('request');
var mime = require('mime-types');
var parseDataURI = require('parse-data-uri');
var images = require('images'); //           

function handlePNG(data, cb) {
     
  var pngData;
  var imageData;
  try {
     
    imageData = images(data);
    pngData = imageData.encode('png'); //      png     ,     ,  png      
    var png = new PNG();
    png.parse(pngData, function (err, img_data) {
      //   png    
      if (err) {
     
        cb(err);
        return;
      }
      cb(
        null,
        ndarray(
          new Uint8Array(img_data.data),
          [img_data.width | 0, img_data.height | 0, 4],
          [4, (4 * img_data.width) | 0, 1],
          0
        )
      );
    });
  } catch (e) {
     
    cb(e);
    return;
  }
}

function handleJPEG(data, cb) {
     
  var jpegData;
  var imageData;
  try {
     
    imageData = images(data);
    //      jpg     ,     ,  jpg      ,   jpeg-js      
    jpegData = jpeg.decode(imageData.encode('jpg'));
  } catch (e) {
     
    cb(e);
    return;
  }
  if (!jpegData) {
     
    cb(new Error('Error decoding jpeg'));
    return;
  }
  var nshape = [jpegData.height, jpegData.width, 4];
  var result = ndarray(jpegData.data, nshape);
  cb(null, result.transpose(1, 0));
}

function handleGIF(data, cb) {
     
  var reader;
  try {
     
    reader = new GifReader(data);
  } catch (err) {
     
    cb(err);
    return;
  }
  if (reader.numFrames() > 0) {
     
    var nshape = [reader.numFrames(), reader.height, reader.width, 4];
    try {
     
      var ndata = new Uint8Array(nshape[0] * nshape[1] * nshape[2] * nshape[3]);
    } catch (err) {
     
      cb(err);
      return;
    }
    var result = ndarray(ndata, nshape);
    try {
     
      for (var i = 0; i < reader.numFrames(); ++i) {
     
        reader.decodeAndBlitFrameRGBA(
          i,
          ndata.subarray(result.index(i, 0, 0, 0), result.index(i + 1, 0, 0, 0))
        );
      }
    } catch (err) {
     
      cb(err);
      return;
    }
    cb(null, result.transpose(0, 2, 1));
  } else {
     
    var nshape = [reader.height, reader.width, 4];
    var ndata = new Uint8Array(nshape[0] * nshape[1] * nshape[2]);
    var result = ndarray(ndata, nshape);
    try {
     
      reader.decodeAndBlitFrameRGBA(0, ndata);
    } catch (err) {
     
      cb(err);
      return;
    }
    cb(null, result.transpose(1, 0));
  }
}

function handleBMP(data, cb) {
     
  var bmp = new Bitmap(data);
  try {
     
    bmp.init();
  } catch (e) {
     
    cb(e);
    return;
  }
  var bmpData = bmp.getData();
  var nshape = [bmpData.getHeight(), bmpData.getWidth(), 4];
  var ndata = new Uint8Array(nshape[0] * nshape[1] * nshape[2]);
  var result = ndarray(ndata, nshape);
  pack(bmpData, result);
  cb(null, result.transpose(1, 0));
}

function doParse(mimeType, data, cb) {
     
  if (mimeType.includes(';')) {
     
    mimeType = mimeType.split(';')[0];
  }
  switch (mimeType) {
     
    case 'image/png':
      handlePNG(data, cb);
      break;

    case 'image/jpg':
    case 'image/jpeg':
      handleJPEG(data, cb);
      break;

    case 'image/gif':
      handleGIF(data, cb);
      break;

    case 'image/bmp':
      handleBMP(data, cb);
      break;

    default:
      cb(new Error('Unsupported file type: ' + mimeType));
  }
}

module.exports = function getPixels(url, type, cb) {
     
  if (!cb) {
     
    cb = type;
    type = '';
  }
  if (Buffer.isBuffer(url)) {
     
    if (!type) {
     
      cb(new Error('Invalid file type'));
      return;
    }
    doParse(type, url, cb);
  } else if (url.indexOf('data:') === 0) {
     
    try {
     
      var buffer = parseDataURI(url);
      if (buffer) {
     
        process.nextTick(function () {
     
          doParse(type || buffer.mimeType, buffer.data, cb);
        });
      } else {
     
        process.nextTick(function () {
     
          cb(new Error('Error parsing data URI'));
        });
      }
    } catch (err) {
     
      process.nextTick(function () {
     
        cb(err);
      });
    }
  } else if (url.indexOf('http://') === 0 || url.indexOf('https://') === 0) {
     
    request({
      url: url, encoding: null }, function (err, response, body) {
     
      if (err) {
     
        cb(err);
        return;
      }

      type = type;
      let imgReg = /\.(png|jpg|jpeg|gif|bmp)/i;
      if (!type) {
     
        if (
          response.getHeader !== undefined &&
          response.getHeader('content-type')
        ) {
     
          type = response.getHeader('content-type');
        } else if (
          response.headers !== undefined &&
          response.headers['content-type']
        ) {
     
          type = response.headers['content-type'];
        } else if (imgReg.test(url)) {
     
          let matchArr = url.match(imgReg);
          type = `image/${
       matchArr[1]}`;
        }
      }
      if (!type) {
     
        cb(new Error('Invalid content-type'));
        return;
      }
      doParse(type, body, cb);
    });
  } else {
     
    fs.readFile(url, function (err, data) {
     
      if (err) {
     
        cb(err);
        return;
      }
      type = type || mime.lookup(url);
      if (!type) {
     
        cb(new Error('Invalid file type'));
        return;
      }
      doParse(type, data, cb);
    });
  }
};

色盤値を取得してエクセルファイルに書き込む
  • は、各ピクチャに対応する色ディスク値をxlsxファイルに書き込み、node-xlsx
  • を使用する.
  • は、色ディスク値に対応する色(セルの背景色の形態で示す)を示す
  • .
    // index.js
    
    const xlsx = require('node-xlsx').default;
    const ColorThief = require('./utils/color-thief-node'); //   Nodejs       ( )
    const fs = require('fs');
    const Color = require('color'); //    rgb -> hex      
    
    const workSheetsFromFile = xlsx.parse(`${
           __dirname}/docs/test.xlsx`); //   xlsx    json      
    
    // workSheetsFromFile[0]['data'][0][5] = '   ';
    
    const getPaletteColor = async () => {
         
        //          
      for (let i = 1; i < workSheetsFromFile[0]['data'].length; i++) {
         
        // getPalette            ,          TOP5
        await ColorThief.getPalette(workSheetsFromFile[0]['data'][i][3], 5)
          .then((palette) => {
         
            console.log('palette', palette);
            workSheetsFromFile[0]['data'][i][4] = JSON.stringify(palette);
            for (let j = 0; j < palette.length; j++) {
         
              const bgColor = Color.rgb(palette[j]).hex().slice(1); //       ,          rgb  
              workSheetsFromFile[0]['data'][i][j + 5] = {
          //         ,      node-xlsx   
                v: bgColor,
                s: {
         
                  fill: {
         
                    fgColor: {
         
                      rgb: bgColor,
                    },
                  },
                },
              };
            }
          })
          .catch((err) => {
         
            console.log(err);
            workSheetsFromFile[0]['data'][i][4] = 0;
          });
      }
    
      const buffer = xlsx.build([
        {
          name: 'Sheet1', data: workSheetsFromFile[0]['data'] },
      ]);
    
      fs.writeFileSync(`${
           __dirname}/docs/test.xlsx`, buffer);
    };
    
    getPaletteColor();
    
    セルの色の設定を修復できませんでした.
    上記のコードを実行すると、セルに設定された背景色が無効であることが分かりました.原因はnode-xlsxがjs-xlsxコミュニティバージョンに依存していますが、有料proバージョンでのみスタイル色の設定がサポートされています.
    しかし、業界ではすでに魔改js-xlsx案があります.最新のJS-XLSXに対応させる形の改造方法を見てください.
    具体的には次のように使います.
    下のファイルを使ってnode_modules/xlsx/xlsx.jsファイルを上書きします.https://github.com/wangerzi/layui-excel/blob/master/src/xlsx.js 下のファイルを使ってnode_modules/xlsx/jszip.jsファイルを上書きします.https://github.com/wangerzi/layui-excel/blob/master/src/jszip.js
    上記の操作により、セルに設定されたスタイルが有効になります.