使用 PHP 创建浮雕效果:在底部边缘添加白色边框,在其他边缘添加黑色边框,图像的其余部分应为 5% 黑色
Use PHP to create embossing effect: add white border to bottom edges and black border to other edges, rest of image should be 5% black
我想知道是否可以使用 PHP 在用户上传的徽标上创建浮雕效果。
效果(根据 Photoshop 部门的说法)可以通过将徽标的内容转换为全黑(因此它将是一种颜色)并使 'layer' 5% 填充(所以基本上它变成 95% 透明)。之后,他们会在徽标的 top/left/right 边缘添加黑色边框,并在徽标的底部边缘添加白色边框。并且只是边缘,而不是图像本身的外部;标识内容的边缘需要描边
由于我在图像处理方面的知名度不高,我想知道是否有一些 PHP 专家可以帮助我 out/point 我在正确的方向上如何做这件事?
所以总结起来,我需要的是4样东西:
- 将图像内容转换为全黑(但保持透明度)
- 使图像透明 95%
- 在图像内容的 top/left/right 边缘添加黑色边框
- 在图像内容的底部边缘添加白色边框
如果可以在 CSS 中为 IE10 及更高版本的浏览器实现,这也是一个很好的解决方案。提前致谢!
编辑
这是艺术家在 image/background/pattern 之上创建的徽标示例:http://picpaste.com/embos-example-ngxfSAj5.png - 他们以与他们最初告诉我他们会做的方式有点不同: ) 在 Photoshop 中,他们添加了一个从上到下的黑色内阴影,以及一个从下到上的白色阴影
看来我问的问题不对.. 将效果从荷兰语 (Preeg) 翻译成英语时,我以为我需要浮雕效果.. 但我发现 PHP function shadeImage 是我想要的。为了帮助其他人,我会 post 我做了什么来实现这一目标。
要使用 shadeImage,您必须提供 black/white 图片。那是我第一次尝试该功能时出错的地方。所以我首先做了一个函数,根据每个像素的 alpha 通道将图像转换为 black/grey/white。之后我使用了 shadeImage。生成的图像确实有背景,必须将其删除。我尝试使用 paintTransparentImage 之类的东西,但在我的所有测试中都没有用,所以我制作了一个自定义函数,通过再次循环每个像素。最后我将所有像素设置为 0.35 的 alpha 通道值,使图像有点 'softer' 并且可以在背景上使用。这是完整的函数:
public function createEmbossedLogo($imagePath, $embossedFilePath) {
// initialize Imagick and load the image
$imagick = new \Imagick(realpath($imagePath));
// make sure we are using PNG, so we can use the alpha channel
$imagick->setImageFormat('png');
// resize the logo, so we do not have to process too many pixels
$imagick->resizeImage(200, null,\Imagick::FILTER_CATROM,1);
// if the image does not have any margin around the content,
// the shade would be cut off at the sides,
// so we add an invisible border of 5 pixels, to add some margin
$imagick->borderImage('rgba(255,0,0,0)',5, 5);
// now we have to convert the image to a black/white image, using only the alpha channel
// and use the alpha channel value as the R/G/B channel values
// load the pixels of the image
$imageIterator = $imagick->getPixelIterator();
foreach ($imageIterator as $row => $pixels) { /* Loop through pixel rows */
foreach ($pixels as $column => $pixel) { /* Loop through the pixels in the row (columns) */
/** @var $pixel \ImagickPixel */
$nor_color = $pixel->getColor(true); //normalized color
// the alpha channel will be 0 if it is completely invisible and 1 if visibile
// but can be any value in between 0-1
// by using the alpha channel as the white/grey/black value, we create an alpha map
$alpha = $nor_color['a'];
$rgbValue = $alpha*255;
$pixel->setColor('rgba('.$rgbValue.','.$rgbValue.','.$rgbValue.',1');
}
$imageIterator->syncIterator(); /* Sync the iterator, this is important to do on each iteration */
}
// add the shading, the first parameter makes sure that all the 'to be removed' pixels
// are the same color, so we can find them in the next loop through all pixels
// they would otherwise be black, one of the colors we do need to keep in the result
$imagick->shadeImage(true,270,45);
// the shadeImage function will make all the pixels grey that should be transparent
// so we loop over all the pixels in the image once again to remove them
$imageIterator = $imagick->getPixelIterator();
$colorFound = false;
$colorRange = 10;
foreach ($imageIterator as $row => $pixels) { /* Loop through pixel rows */
foreach ($pixels as $column => $pixel) { /* Loop through the pixels in the row (columns) */
/** @var $pixel \ImagickPixel */
$color = $pixel->getColor(); //normalized color
if (!$colorFound) {
// since added some margin around the image, we can take the first pixel
// of the top left corner, and use it as the color to make transparent
// and since the image is in black/white, we only need one 'color' channel
$colorFound = array();
$colorFound['r'] = $color['r'];
}
// the default alpha for pixels to keep is 1
$alpha = 1;
// see if the color of this pixel is close to that of the 'color to be deleted'
// if so, we will not totally delete it, but change the alpha channel accordingly
$diff = abs($color['r']-$colorFound['r']);
if ($diff<=$colorRange) {
// set alpha value for this pixel, based on the difference from the removed color
$alpha = $diff / $colorRange;
}
// the entire opacity of the image has to brought down, to make the image a bit 'softer'
$alpha *= 0.35;
// this pixel matches the 'to be removed' color, so we set it to a new value with alpha 0
$pixel->setColor('rgba('.$color['r'].','.$color['g'].','.$color['b'].','.$alpha.')');
}
$imageIterator->syncIterator(); /* Sync the iterator, this is important to do on each iteration */
}
// remove any excess margins that are not needed
$imagick->trimImage(0);
// store the image
$imagick->writeImage($embossedFilePath);
}
我想知道是否可以使用 PHP 在用户上传的徽标上创建浮雕效果。
效果(根据 Photoshop 部门的说法)可以通过将徽标的内容转换为全黑(因此它将是一种颜色)并使 'layer' 5% 填充(所以基本上它变成 95% 透明)。之后,他们会在徽标的 top/left/right 边缘添加黑色边框,并在徽标的底部边缘添加白色边框。并且只是边缘,而不是图像本身的外部;标识内容的边缘需要描边
由于我在图像处理方面的知名度不高,我想知道是否有一些 PHP 专家可以帮助我 out/point 我在正确的方向上如何做这件事?
所以总结起来,我需要的是4样东西:
- 将图像内容转换为全黑(但保持透明度)
- 使图像透明 95%
- 在图像内容的 top/left/right 边缘添加黑色边框
- 在图像内容的底部边缘添加白色边框
如果可以在 CSS 中为 IE10 及更高版本的浏览器实现,这也是一个很好的解决方案。提前致谢!
编辑
这是艺术家在 image/background/pattern 之上创建的徽标示例:http://picpaste.com/embos-example-ngxfSAj5.png - 他们以与他们最初告诉我他们会做的方式有点不同: ) 在 Photoshop 中,他们添加了一个从上到下的黑色内阴影,以及一个从下到上的白色阴影
看来我问的问题不对.. 将效果从荷兰语 (Preeg) 翻译成英语时,我以为我需要浮雕效果.. 但我发现 PHP function shadeImage 是我想要的。为了帮助其他人,我会 post 我做了什么来实现这一目标。
要使用 shadeImage,您必须提供 black/white 图片。那是我第一次尝试该功能时出错的地方。所以我首先做了一个函数,根据每个像素的 alpha 通道将图像转换为 black/grey/white。之后我使用了 shadeImage。生成的图像确实有背景,必须将其删除。我尝试使用 paintTransparentImage 之类的东西,但在我的所有测试中都没有用,所以我制作了一个自定义函数,通过再次循环每个像素。最后我将所有像素设置为 0.35 的 alpha 通道值,使图像有点 'softer' 并且可以在背景上使用。这是完整的函数:
public function createEmbossedLogo($imagePath, $embossedFilePath) {
// initialize Imagick and load the image
$imagick = new \Imagick(realpath($imagePath));
// make sure we are using PNG, so we can use the alpha channel
$imagick->setImageFormat('png');
// resize the logo, so we do not have to process too many pixels
$imagick->resizeImage(200, null,\Imagick::FILTER_CATROM,1);
// if the image does not have any margin around the content,
// the shade would be cut off at the sides,
// so we add an invisible border of 5 pixels, to add some margin
$imagick->borderImage('rgba(255,0,0,0)',5, 5);
// now we have to convert the image to a black/white image, using only the alpha channel
// and use the alpha channel value as the R/G/B channel values
// load the pixels of the image
$imageIterator = $imagick->getPixelIterator();
foreach ($imageIterator as $row => $pixels) { /* Loop through pixel rows */
foreach ($pixels as $column => $pixel) { /* Loop through the pixels in the row (columns) */
/** @var $pixel \ImagickPixel */
$nor_color = $pixel->getColor(true); //normalized color
// the alpha channel will be 0 if it is completely invisible and 1 if visibile
// but can be any value in between 0-1
// by using the alpha channel as the white/grey/black value, we create an alpha map
$alpha = $nor_color['a'];
$rgbValue = $alpha*255;
$pixel->setColor('rgba('.$rgbValue.','.$rgbValue.','.$rgbValue.',1');
}
$imageIterator->syncIterator(); /* Sync the iterator, this is important to do on each iteration */
}
// add the shading, the first parameter makes sure that all the 'to be removed' pixels
// are the same color, so we can find them in the next loop through all pixels
// they would otherwise be black, one of the colors we do need to keep in the result
$imagick->shadeImage(true,270,45);
// the shadeImage function will make all the pixels grey that should be transparent
// so we loop over all the pixels in the image once again to remove them
$imageIterator = $imagick->getPixelIterator();
$colorFound = false;
$colorRange = 10;
foreach ($imageIterator as $row => $pixels) { /* Loop through pixel rows */
foreach ($pixels as $column => $pixel) { /* Loop through the pixels in the row (columns) */
/** @var $pixel \ImagickPixel */
$color = $pixel->getColor(); //normalized color
if (!$colorFound) {
// since added some margin around the image, we can take the first pixel
// of the top left corner, and use it as the color to make transparent
// and since the image is in black/white, we only need one 'color' channel
$colorFound = array();
$colorFound['r'] = $color['r'];
}
// the default alpha for pixels to keep is 1
$alpha = 1;
// see if the color of this pixel is close to that of the 'color to be deleted'
// if so, we will not totally delete it, but change the alpha channel accordingly
$diff = abs($color['r']-$colorFound['r']);
if ($diff<=$colorRange) {
// set alpha value for this pixel, based on the difference from the removed color
$alpha = $diff / $colorRange;
}
// the entire opacity of the image has to brought down, to make the image a bit 'softer'
$alpha *= 0.35;
// this pixel matches the 'to be removed' color, so we set it to a new value with alpha 0
$pixel->setColor('rgba('.$color['r'].','.$color['g'].','.$color['b'].','.$alpha.')');
}
$imageIterator->syncIterator(); /* Sync the iterator, this is important to do on each iteration */
}
// remove any excess margins that are not needed
$imagick->trimImage(0);
// store the image
$imagick->writeImage($embossedFilePath);
}