- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我需要在 ImageMagick 中创建一个模仿 Adobe Photoshop 的“颜色”混合模式的命令,以便为图像着色。为了做到这一点,我试图合成原始图像和另一个由全彩色层组成的图像,不透明度为 35%。这应该与原始图像融合并创建彩色结果图像。
这是预期的结果:
Adobe 网站上正在定义“颜色”混合模式,如下所示:“使用基色的亮度以及混合色的色调和饱和度创建结果颜色。这会保留图像中的灰度级,并且可用于为单色图像着色和为彩色图像着色。”
ImageMagick 中定义了一个 compose 方法,它似乎做同样的事情(Luminize),但结果远非预期的那样。
在 Imagemagick 中提供最接近结果的似乎是默认的混合 compose 方法,使用如下:
convert image.jpg color_layer.png -compose blend -composite result.jpg
最佳答案
基于 CaSTLes 有值(value)的答案,我试图找到在 PHP 中执行此操作的最佳解决方案。他引用的实现有两个主要缺陷:一个是它没有考虑不透明度(如果有的话),第二个是非常缓慢且耗费资源。在 PHP 中处理 500x500 像素的图像大约需要 15 秒,其中 Apache 将保持处理器高达 95%。
我发现最快和最少的资源消耗实际上是在 HTML5 中使用 Canvas 处理图像。结果令人惊叹,图像正在现场处理。
我将在最后的代码块下方发布,一个用于 PHP,一个用于 HTML。如果您需要使用此服务器端,您可以将 HTML 代码复制粘贴到 Node.js 和 NodeCanvas 中:https://github.com/LearnBoost/node-canvas
PHP(不透明):
<?php
function Lum($colour) {
return ($colour['r'] * 0.3) + ($colour['g'] * 0.59) + ($colour['b'] * 0.11);
}
function ClipColour($colour) {
$result = $colour;
$luminance = Lum($colour);
$cMin = min($colour['r'], $colour['g'], $colour['b']);
$cMax = max($colour['r'], $colour['g'], $colour['b']);
if ($cMin < 0.0) {
$result['r'] = $luminance + ((($colour['r'] - $luminance) * $luminance) / ($luminance - $cMin));
$result['g'] = $luminance + ((($colour['g'] - $luminance) * $luminance) / ($luminance - $cMin));
$result['b'] = $luminance + ((($colour['b'] - $luminance) * $luminance) / ($luminance - $cMin));
}
if ($cMax > 255) {
$result['r'] = $luminance + ((($colour['r'] - $luminance) * (255 - $luminance)) / ($cMax - $luminance));
$result['g'] = $luminance + ((($colour['g'] - $luminance) * (255 - $luminance)) / ($cMax - $luminance));
$result['b'] = $luminance + ((($colour['b'] - $luminance) * (255 - $luminance)) / ($cMax - $luminance));
}
return $result;
}
function SetLum($colour, $luminance) {
$result = array();
$diff = $luminance - Lum($colour);
$result['r'] = $colour['r'] + $diff;
$result['g'] = $colour['g'] + $diff;
$result['b'] = $colour['b'] + $diff;
return ClipColour($result);
}
function normalizeColor( $color ) {
$color['r'] = $color['r'] / 255;
$color['g'] = $color['g'] / 255;
$color['b'] = $color['b'] / 255;
return $color;
}
function denormalizeColor( $color ) {
$color['r'] = round($color['r'] * 255);
$color['g'] = round($color['g'] * 255);
$color['b'] = round($color['b'] * 255);
return $color;
}
$overlay_color = array('r'=>180,'g'=>22,'b'=>1, 'a' => 0.35);
$img = new Imagick();
if( !isset($_GET['case']) ) {
$_GET['case'] = '';
}
//unmodified version
$original = new Imagick('girl.jpg');
//photoshop image to compare
$ps = new Imagick('original.jpg');
$img->addImage($original);
$it = $original->getPixelIterator();
foreach( $it as $row => $pixels ) {
foreach ( $pixels as $column => $pixel ) {
$rgbIni = $pixel->getColor();
$rgb = SetLum($overlay_color, Lum($rgbIni));
$overlay_color = normalizeColor($overlay_color);
$rgb = normalizeColor($rgb);
$rgbIni = normalizeColor($rgbIni);
$rgb['r'] = ((1 - $overlay_color['a']) * $rgbIni['r']) + ($overlay_color['a'] * $rgb['r']);
$rgb['g'] = ((1 - $overlay_color['a']) * $rgbIni['g']) + ($overlay_color['a'] * $rgb['g']);
$rgb['b'] = ((1 - $overlay_color['a']) * $rgbIni['b']) + ($overlay_color['a'] * $rgb['b']);
$test = denormalizeColor($test);
$rgb = denormalizeColor($rgb);
$overlay_color = denormalizeColor($overlay_color);
$pixel->setColor('rgb('.round($rgb['r']).','. round($rgb['g']).','.round($rgb['b']).')');
}
$it->syncIterator();
}
//add modified version
$img->addImage($original);
$img->addImage($ps);
$img->resetIterator();
$combined = $img->appendImages(true); //stack images
header('content-type: image/jpeg');
$combined->setImageFormat("jpeg");
echo $combined;
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<script>
var RGBA = function(r, g, b, a) {
this.R = r || 0;
this.G = g || 0;
this.B = b || 0;
this.A = a || 0.5;
}
function SetLum(initialColor, pixelColor) {
var initalColorLuminance = initialColor.R * 0.3 + initialColor.G * 0.59 + initialColor.B * 0.11;
var pixelColorLuminance = pixelColor.R * 0.3 + pixelColor.G * 0.59 + pixelColor.B * 0.11;
var diff = pixelColorLuminance - initalColorLuminance;
var response = new Array;
response[0] = initialColor.R + diff;
response[1] = initialColor.G + diff;
response[2] = initialColor.B + diff;
//console.log(response[0]);
return ClipColour(response);
}
function alphaComposite(mv, ov, a) {
return (mv * a) + (ov * (1 - a));
}
function ClipColour(color) { //function to prevent underexposure or overexposure on some pixels
var result = color;
var luminance = color[0] * 0.3 + color[1] * 0.59 + color[1] * 0.11;
var cMin = Math.min(color[0], color[1], color[2]);
var cMax = Math.max(color[0], color[1], color[2]);
if (cMin < 0.0) {
color[0] = luminance + (((color[0] - luminance) * luminance) / (luminance - cMin));
color[1] = luminance + (((color[1] - luminance) * luminance) / (luminance - cMin));
color[2] = luminance + (((color[2] - luminance) * luminance) / (luminance - cMin));
}
if (cMax > 255) {
color[0] = luminance + (((color[0] - luminance) * (255 - luminance)) / (cMax - luminance));
color[1] = luminance + (((color[1] - luminance) * (255 - luminance)) / (cMax - luminance));
color[2] = luminance + (((color[2] - luminance) * (255 - luminance)) / (cMax - luminance));
}
return color;
}
function processImage(image, targetColour) {
var canvas = document.createElement('canvas');
c = canvas.getContext('2d');
canvas.width = image.width;
canvas.height = image.height;
// Draw the building on the original canvas
c.drawImage(image, 0, 0, canvas.width, canvas.height);
// There's a (much) faster way to cycle through all the pixels using typed arrays,
// but I'm playing it safe so that the example works in all browsers.
var imageData = c.getImageData(0, 0, canvas.width, canvas.height),
imageDataPixels = imageData.data;
for (var i = 0, len = imageDataPixels.length; i < len; i += 4) {
var pixelColor = new RGBA(imageDataPixels[i], imageDataPixels[i+1], imageDataPixels[i+2], 1);
var test = SetLum(targetColour, pixelColor);
var r = Math.round(test[0]);
var g = Math.round(test[1]);
var b = Math.round(test[2]);
imageDataPixels[i] = alphaComposite(r, imageDataPixels[i], targetColour.A);
imageDataPixels[i + 1] = alphaComposite(g, imageDataPixels[i + 1], targetColour.A);
imageDataPixels[i + 2] = alphaComposite(b, imageDataPixels[i + 2], targetColour.A);
}
c.putImageData(imageData, 0, 0);
return canvas;
}
document.addEventListener('DOMContentLoaded', function() {
var image = new Image(),
processImageFile = null;
image.src = "girl.jpg";
image.addEventListener('load', function() {
var canvas = document.getElementById('canvas'),
c = canvas.getContext('2d'),
imageRGBA = new RGBA(180, 22, 1, 0.35);
canvas.width = image.width;
canvas.height = image.height;
c.drawImage(image, 0, 0);
processImageFile = processImage(image, imageRGBA);
c.drawImage(processImageFile, 0, 0);
});
});
</script>
</head>
<body>
<img src="girl.jpg" />
<br />
<canvas id="canvas"></canvas>
<br />
<img src="original.jpg" />
</body>
关于imagemagick - 在 ImageMagick 中复制 Photoshop 的 "Color"混合模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11973086/
为大型网站创建所有艺术作品通常涉及几十个 50+mb 的 Photoshop 文件。通常,给定的模块可能出现在多个文件中。 有没有办法从另一个文件引用经常使用的模块? 例如 -“site-sectio
关闭。这个问题是off-topic .它目前不接受答案。 想改进这个问题吗? Update the question所以它是on-topic用于堆栈溢出。 关闭 11 年前。 Improve thi
我是 Photoshop 脚本的新手。 我想将图像图像(从我的硬盘)作为带有定位的新图层加载到事件文档中。如何才能做到这一点?有人可以分享代码吗? 谢谢 最佳答案 您可以打开 Photoshop 文件
在 photoshop 中,假设我有一些文本图层,其内容如下: Text layer 1: 1@@text01@@abc Text layer 2: 2@@text02@@cef Text lay
我在 Photoshop 中有 500 个图标图像,每个对象周围都有不同的空白区域。我想知道是否有任何方法可以通过 photoshop 运行一个 Action 来裁剪每个图像,以便它删除每个图标周围的
我在 Photoshop 中有 6 个组,每个组中包含多个图层。我希望打开/关闭每个组中的图层以创建图像的所有可能组合。 有人能指出我正确的方向吗? 我从来没有在 Photoshop 中编写过脚本,而
我想开始用 Photoshop 做一些脚本,我想知道是否有一个编辑器已经拥有 Photoshop 的对象或允许加载 Photoshop 的 DOM 以进行智能感知。 任何指针? 最佳答案 Adobe
几乎从一开始,Photoshop 文件就以 8BPS 开始。 (我已经在 2.5 版本中验证了这一点)它在某些时候一定具有某种意义。 我认为 8B 可能指的是位/ channel ,但保存为 16 或
如何在Photoshop中使用Javascript获取/设置当前工具? #target photoshop if (app.currentTool == BRUSH_TOOL) { app.c
几乎从一开始,Photoshop 文件就以 8BPS 开始。 (我已经验证回 2.5 版)它一定在某些时候有一些意义。 我认为 8B 可能指的是位/ channel ,但保存为 16 或 32 没有区
关闭。这个问题是off-topic .它目前不接受答案。 想改善这个问题吗? Update the question所以它是 on-topic对于堆栈溢出。 8 年前关闭。 Improve this
我有非常大的 1 位图像,我需要在 Photoshop 中写入文本数组。我可以在 javascript 中通过将图像转换为灰度然后为每个文本 block 创建一个新层来执行此操作,但我希望能够将文本直
如果我有一个具有以下设置的 photoshop 投影 Blend Mode - rgb(0,0,0) / Opacity - 25% / Angle - 135 degrees / Distance
我正在编写一个脚本,它将遍历图层,修剪它们并导出。到目前为止,我拥有完成此脚本所需的大部分元素。我唯一找不到的是如何显示/隐藏单个图层。我找到了显示/隐藏所有图层的功能,但对于单个图层没有任何功能。
如何在不裁剪的情况下查看矩形选取框选定区域的大小?在paint.net中这很容易,但我必须在photoshop cs 5中完成。在选择区域时,我应该能够看到所选区域的尺寸。我怎样才能做到这一点? 此外
在实现单选按钮时遇到问题。我知道 CS2 中的单选按钮可能有问题,但我不确定哪里出错了。我怀疑我的括号或逗号放错地方了;但看不到它。谢谢。 var dlg = "dialog {text:'Scrip
每种文件格式的技术规范/功能是什么? 一种类型是否比另一种更好地处理某些类型的图形? 最佳答案 XCF 支持保存每一层、当前选择、 channel 、透明度、路径和指南。但是,与 Adobe Ph
我希望 Photoshop 为给定的文件夹自动执行以下任务: 加载给定文件夹中的所有 PNG 文件。 将每个文件的模式转换为RGB 颜色 为每个文件添加一层 在同一文件夹中将文件另存为 PSD 有人告
我第一次编写一些 Photoshop 脚本,如果有一个类似 console.log 的函数来在 ExtendScript Toolkit App 的 Javascript 控制台中输出数组和对象值,那
我不知道如何将我为按钮制作的 Photoshop 形状导入 android,而不带背景。即使我将 photoshop 中的背景设置为透明并将其另存为 PNG,当我在 android 中将它用作我的按钮
我是一名优秀的程序员,十分优秀!