bgr*_*ter 107 javascript image-manipulation
不确定这是否可行,但希望编写一个可以返回图像平均值hex
或rgb
值的脚本.我知道它可以在AS中完成,但希望在JavaScript中完成.
Jam*_*mes 137
AFAIK,唯一的方法就是<canvas/>
......
DEMO V2:http://jsfiddle.net/xLF38/818/
请注意,这仅适用于同一域和支持HTML5画布的浏览器中的图像:
function getAverageRGB(imgEl) {
var blockSize = 5, // only visit every 5 pixels
defaultRGB = {r:0,g:0,b:0}, // for non-supporting envs
canvas = document.createElement('canvas'),
context = canvas.getContext && canvas.getContext('2d'),
data, width, height,
i = -4,
length,
rgb = {r:0,g:0,b:0},
count = 0;
if (!context) {
return defaultRGB;
}
height = canvas.height = imgEl.naturalHeight || imgEl.offsetHeight || imgEl.height;
width = canvas.width = imgEl.naturalWidth || imgEl.offsetWidth || imgEl.width;
context.drawImage(imgEl, 0, 0);
try {
data = context.getImageData(0, 0, width, height);
} catch(e) {
/* security error, img on diff domain */
return defaultRGB;
}
length = data.data.length;
while ( (i += blockSize * 4) < length ) {
++count;
rgb.r += data.data[i];
rgb.g += data.data[i+1];
rgb.b += data.data[i+2];
}
// ~~ used to floor values
rgb.r = ~~(rgb.r/count);
rgb.g = ~~(rgb.g/count);
rgb.b = ~~(rgb.b/count);
return rgb;
}
Run Code Online (Sandbox Code Playgroud)
对于IE,请查看excanvas.
小智 49
"显性颜色"很棘手.你想要做的是比较每个像素与颜色空间中每个其他像素之间的距离(欧氏距离),然后找到颜色最接近其他颜色的像素.该像素是主色.平均颜色通常是泥.
我希望我在这里有MathML向你展示Euclidean Distance.谷歌一下.
我已经使用PHP/GD在RGB颜色空间中完成了上述执行:https://gist.github.com/cf23f8bddb307ad4abd8
然而,这在计算上非常昂贵.它会使您的系统在大图像上崩溃,如果您在客户端中尝试它,肯定会使您的浏览器崩溃.我一直在努力将我的执行重构为: - 将结果存储在查找表中,以便将来在每个像素的迭代中使用. - 将大图像划分为20px 20px的网格,以实现局部优势. - 使用x1y1和x1y2之间的欧氏距离来计算x1y1和x1y3之间的距离.
如果你在这方面取得进展,请告诉我.我很乐意看到它.我也会这样做.
Canvas绝对是在客户端中执行此操作的最佳方式.SVG不是,SVG是基于矢量的.在我执行下来之后,接下来要做的就是让它在画布中运行(可能每个像素的整体距离计算都有一个webworker).
需要考虑的另一件事是RGB不是一个很好的色彩空间,因为RGB空间中的颜色之间的欧氏距离不是非常接近视距.这样做的更好的颜色空间可能是LUV,但我没有找到一个好的库,或者没有找到将RGB转换为LUV的任何算法.
一种完全不同的方法是在彩虹中对颜色进行排序,并构建一个具有容差的直方图,以适应不同颜色的阴影.我没试过这个,因为在彩虹中排序颜色很难,颜色直方图也是如此.我可能会尝试下一步.再次,如果您在这里取得任何进展,请告诉我.
And*_*ass 15
第一:它可以在没有HTML5 Canvas或SVG的情况下完成.
实际上,有人使用数据URI方案设法使用JavaScript(没有画布或SVG)生成客户端PNG文件.
第二:你可能根本不需要Canvas,SVG或任何上述任何一种.
如果您只需要在客户端处理图像而不修改它们,则不需要所有这些.
您可以从页面上的img标记获取源地址,为它发出XHR请求 - 它很可能来自浏览器缓存 - 并将其作为来自Javascript的字节流进行处理.
您需要很好地理解图像格式.(上面的生成器部分基于libpng源,可能提供一个很好的起点.)
我会说通过HTML canvas标签.
你可以在这里找到@Georg的一篇文章,谈论Opera dev的一个小代码:
// Get the CanvasPixelArray from the given coordinates and dimensions.
var imgd = context.getImageData(x, y, width, height);
var pix = imgd.data;
// Loop over each pixel and invert the color.
for (var i = 0, n = pix.length; i < n; i += 4) {
pix[i ] = 255 - pix[i ]; // red
pix[i+1] = 255 - pix[i+1]; // green
pix[i+2] = 255 - pix[i+2]; // blue
// i+3 is alpha (the fourth element)
}
// Draw the ImageData at the given (x,y) coordinates.
context.putImageData(imgd, x, y);
Run Code Online (Sandbox Code Playgroud)
这通过使用每个像素的R,G和B值来反转图像.您可以轻松存储RGB值,然后向上舍入红色,绿色和蓝色数组,最后将它们转换回HEX代码.
在datauri
支持下获得图像平均颜色的不太准确但最快的方法:
function get_average_rgb(img) {
var context = document.createElement('canvas').getContext('2d');
if (typeof img == 'string') {
var src = img;
img = new Image;
img.setAttribute('crossOrigin', '');
img.src = src;
}
context.imageSmoothingEnabled = true;
context.drawImage(img, 0, 0, 1, 1);
return context.getImageData(1, 1, 1, 1).data.slice(0,3);
}
Run Code Online (Sandbox Code Playgroud)
这是@350D的答案,但异步(因为某些图像可能需要时间加载)并且在打字稿中
async function get_average_rgb(src: string): Promise<Uint8ClampedArray> {
/* /sf/ask/177903701/ */
return new Promise(resolve => {
let context = document.createElement('canvas').getContext('2d');
context!.imageSmoothingEnabled = true;
let img = new Image;
img.src = src;
img.crossOrigin = "";
img.onload = () => {
context!.drawImage(img, 0, 0, 1, 1);
resolve(context!.getImageData(0, 0, 1, 1).data.slice(0,3));
};
});
}
Run Code Online (Sandbox Code Playgroud)
我最近遇到了一个jQuery插件,它实现了我最初想要的https://github.com/briangonzalez/jquery.adaptive-backgrounds.js,从图像中获取支配颜色.
我个人会将Color Thief与Name that Color的修改版本结合起来,以获得足够多的图像主色结果。
例子:
考虑下图:
您可以使用以下代码提取与主色相关的图像数据:
let color_thief = new ColorThief();
let sample_image = new Image();
sample_image.onload = () => {
let result = ntc.name('#' + color_thief.getColor(sample_image).map(x => {
const hex = x.toString(16);
return hex.length === 1 ? '0' + hex : hex;
}).join(''));
console.log(result[0]); // #f0c420 : Dominant HEX/RGB value of closest match
console.log(result[1]); // Moon Yellow : Dominant specific color name of closest match
console.log(result[2]); // #ffff00 : Dominant HEX/RGB value of shade of closest match
console.log(result[3]); // Yellow : Dominant color name of shade of closest match
console.log(result[4]); // false : True if exact color match
};
sample_image.crossOrigin = 'anonymous';
sample_image.src = document.getElementById('sample-image').src;
Run Code Online (Sandbox Code Playgroud)
编辑:仅在发布此内容后,我才意识到@350D 的答案完全相同。
令人惊讶的是,这只需 4 行代码即可完成:
const canvas = document.getElementById("canvas"),
preview = document.getElementById("preview"),
ctx = canvas.getContext("2d");
canvas.width = 1;
canvas.height = 1;
preview.width = 400;
preview.height = 400;
function getDominantColor(imageObject) {
//draw the image to one pixel and let the browser find the dominant color
ctx.drawImage(imageObject, 0, 0, 1, 1);
//get pixel color
const i = ctx.getImageData(0, 0, 1, 1).data;
console.log(`rgba(${i[0]},${i[1]},${i[2]},${i[3]})`);
console.log("#" + ((1 << 24) + (i[0] << 16) + (i[1] << 8) + i[2]).toString(16).slice(1));
}
// vvv all of this is to just get the uploaded image vvv
const input = document.getElementById("input");
input.type = "file";
input.accept = "image/*";
input.onchange = event => {
const file = event.target.files[0];
const reader = new FileReader();
reader.onload = readerEvent => {
const image = new Image();
image.onload = function() {
//shows preview of uploaded image
preview.getContext("2d").drawImage(
image,
0,
0,
preview.width,
preview.height,
);
getDominantColor(image);
};
image.src = readerEvent.target.result;
};
reader.readAsDataURL(file, "UTF-8");
};
Run Code Online (Sandbox Code Playgroud)
canvas {
width: 200px;
height: 200px;
outline: 1px solid #000000;
}
Run Code Online (Sandbox Code Playgroud)
<canvas id="preview"></canvas>
<canvas id="canvas"></canvas>
<input id="input" type="file" />
Run Code Online (Sandbox Code Playgroud)
这个怎么运作:
创建画布上下文
const context = document.createElement("canvas").getContext("2d");
Run Code Online (Sandbox Code Playgroud)
这会将图像仅绘制到一个画布像素,使浏览器为您找到主色。
context.drawImage(imageObject, 0, 0, 1, 1);
Run Code Online (Sandbox Code Playgroud)
之后,只需获取像素的图像数据:
const i = context.getImageData(0, 0, 1, 1).data;
Run Code Online (Sandbox Code Playgroud)
最后,转换为rgba
or HEX
:
const rgba = `rgba(${i[0]},${i[1]},${i[2]},${i[3]})`;
const HEX = "#" + ((1 << 24) + (i[0] << 16) + (i[1] << 8) + i[2]).toString(16).slice(1);
Run Code Online (Sandbox Code Playgroud)
但是这种方法有一个问题,那就是getImageData
有时会抛出错误Unable to get image data from canvas because the canvas has been tainted by cross-origin data.
,这就是你需要在演示中上传图片而不是输入 URL 的原因。
这种方法也可以用于通过增加宽度和高度来绘制图像来像素化图像。
这适用于 chrome,但可能不适用于其他浏览器。
归档时间: |
|
查看次数: |
114055 次 |
最近记录: |