Nodejs抽出画像のテーマ色(一)
需要正常にアクセスできる画像リンク は、ピクチャデータ値のグレー系rgbの値(すなわち を排除する..残りのrgb値を集計して、色ランキング を導出した.ここでは主に参考になります.https://github.com/lokesh/color-thief オープンソース 下編はNodejsに会ってピクチャーのテーマ色を抽出します(2) 使い方
ここは画像の色の値を統計するところでブロック処理をします.
修正の原因はピクチャの である.は、
この中の具体的な問題は
r=g=b
の値)ColorThief.getColor('https://lokeshdhakar.com/projects/color-thief/images/image-1.jpg')
.then((color) => {
console.log('color', color); // ( )
})
.catch((err) => {
console.log(err);
});
ColorThief.getPalette('https://lokeshdhakar.com/projects/color-thief/images/image-1.jpg', 5)
.then((palette) => {
console.log('palette', palette); // ( 5 )
})
.catch((err) => {
console.log(err);
});
どのように画像データ値のグレー系rgbの値を削除しますか?ここは画像の色の値を統計するところでブロック処理をします.
// color-thief color-thief-node.js
const quantize = require('quantize');
const getPixels = require('./node-pixels');
function createPixelArray(imgData, pixelCount, quality) {
const pixels = imgData;
const pixelArray = [];
for (let i = 0, offset, r, g, b, a; i < pixelCount; i = i + quality) {
offset = i * 4;
r = pixels[offset + 0];
g = pixels[offset + 1];
b = pixels[offset + 2];
a = pixels[offset + 3];
if (typeof a === 'undefined' || a >= 125) {
//
if (r !== g || r !== b) {
pixelArray.push([r, g, b]);
}
}
}
return pixelArray;
}
function validateOptions(options) {
let {
colorCount, quality } = options;
if (typeof colorCount === 'undefined' || !Number.isInteger(colorCount)) {
colorCount = 10;
} else if (colorCount === 1 ) {
throw new Error('colorCount should be between 2 and 20. To get one color, call getColor() instead of getPalette()');
} else {
colorCount = Math.max(colorCount, 2);
colorCount = Math.min(colorCount, 20);
}
if (typeof quality === 'undefined' || !Number.isInteger(quality) || quality < 1) {
quality = 10;
}
return {
colorCount,
quality
}
}
function loadImg(img) {
return new Promise((resolve, reject) => {
getPixels(img, function(err, data) {
if(err) {
reject(err)
} else {
resolve(data);
}
})
});
}
function getColor(img, quality) {
return new Promise((resolve, reject) => {
getPalette(img, 5, quality)
.then(palette => {
resolve(palette[0]);
})
.catch(err => {
reject(err);
})
});
}
function getPalette(img, colorCount = 10, quality = 10) {
const options = validateOptions({
colorCount,
quality
});
return new Promise((resolve, reject) => {
loadImg(img)
.then(imgData => {
const pixelCount = imgData.shape[0] * imgData.shape[1];
const pixelArray = createPixelArray(imgData.data, pixelCount, options.quality);
const cmap = quantize(pixelArray, options.colorCount);
const palette = cmap? cmap.palette() : null;
resolve(palette);
})
.catch(err => {
reject(err);
})
});
}
module.exports = {
getColor,
getPalette
};
上のファイルでは、グレー系の値を排除するロジックを修正した以外に、もう一つの違いがあります.const getPixels = require('./node-pixels');
テキストの使用const getPixels = require('get-pixels');
私たちはget-pixels
のこのカバンにいくつかの追加的な修正が必要です.修正の原因は
mimeType
は、image/jpeg;charset=UTF-8
などの文字コードを有することがあり得るが、期待されるのはimage/jpeg
jpg、jpeg
のピクチャ処理について、しばしばエラーを報告しています.特に、第三者によって処理されたピクチャ、例えば(裁断、つなぎ合わせをした後)、エラーを報告するのはthrow new Error("SOI not found");
で、jpgピクチャ規格に合わないという意味です.// node-pixels.js
'use strict';
var ndarray = require('ndarray');
var path = require('path');
var PNG = require('pngjs').PNG;
// var jpeg = require('jpeg-js'); // jpg、jpeg , jpeg-js , images
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'); // images jpg、jpeg
function handlePNG(data, cb) {
var png = new PNG();
png.parse(data, function (err, img_data) {
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
)
);
});
}
function handleJPEG(data, cb) {
var jpegData;
var imageData;
try {
// jpegData = jpeg.decode(data); jpeg-js , images
imageData = images(data);
jpegData = imageData.encode('jpg'); // jpg , 2
} catch (e) {
cb(e);
return;
}
if (!jpegData) {
cb(new Error('Error decoding jpeg'));
return;
}
var nshape = [imageData.height(), imageData.width(), 4];
var result = ndarray(jpegData, 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) {
// mime , 1
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;
if (!type) {
if (response.getHeader !== undefined) {
type = response.getHeader('content-type');
} else if (response.headers !== undefined) {
type = response.headers['content-type'];
}
}
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);
});
}
};
2
を修復する時にimages
というカバンを使いました.そうすると、次の色ディスクの値が得られます.[ [ 195, 170, 172 ],
[ 36, 154, 139 ],
[ 184, 35, 149 ],
[ 174, 186, 34 ],
[ 95, 171, 171 ] ]
実際の写真と比較したところ、この色盤の値は多く一致していないことが分かりました.しかも、差がはっきりしています.この中の具体的な問題は
images
にあり、コードの最適化を経て、画像と一致する値が生成された.[ [ 125, 190, 192 ],
[ 213, 191, 131 ],
[ 53, 37, 27 ],
[ 129, 123, 58 ],
[ 42, 125, 148 ] ]
コード最適化はNodejsを見て写真の主題色を抽出する(二)