douciwang6819 2015-07-17 07:53
浏览 251
已采纳

使用PHP创建浮雕效果:向底边添加白色边框,向其他边添加黑色边框,其余图像应为5%黑色

I would like to know if it is possible to use PHP to create an embossing effect on a user uploaded logo.

The effect (according to the Photoshop department) could be achieved by transforming the contents of the logo to all black (so it will be one color), and make that 'layer' 5% filled (so basically it becomes 95% transparent). After that they would add a black border to the top/left/right edges of the logo, and a white border to the bottom edge of the logo. And just the edges, not the outside of the image itself; the edges of the content of the logo needs to be traced.

As I am not well known in image processing, I was wondering if some PHP expert could help me out/point me in the right direction on how to do this?

So to sum it up, what I need is 4 things:

  • Convert contents of image to all black (but keep transparency)
  • Make the image 95% transparent
  • Add a black border to the top/left/right edges of contents of image
  • Add a white border to the bottom edges of contents of image

If this could be achieved in CSS for browsers from IE10 and up, it would be a good solution as well. Thanks in advance!

EDIT

Here is an example of a logo created by the artists, on top of an image/background/pattern: http://picpaste.com/embos-example-ngxfSAj5.png - they did it in a bit different way as they first told me they would do :) in Photoshop they added a inner shadow in black from the top to down, and a drop shadow in white from bottom to top

  • 写回答

1条回答 默认 最新

  • dphe5602 2015-07-21 09:44
    关注

    It seems I was not asking the right questions.. When translating the effect from Dutch (Preeg) to English, I thought I was in need of an embossing effect.. But I found that the PHP function shadeImage was what I wanted. In order to help other people, I'll post what I did to achieve this.

    To use shadeImage, you have to supply a black/white image. That is where I went wrong when first trying out that function. So I first made a function to translate an image to black/grey/white, based on the alpha channel of each pixel. After that I used shadeImage. The resulting image did have a background, that had to be removed. I tried using things like paintTransparentImage, but that did not work in all my tests, so I made a custom function, by looping over each pixel once again. And finally I set all pixels to an alpha channel value of 0.35, to make the image a bit 'softer' and usable on a background. Here is the complete function:

        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);
        }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 寻一个支付宝扫码远程授权登录的软件助手app
  • ¥15 解riccati方程组
  • ¥15 display:none;样式在嵌套结构中的已设置了display样式的元素上不起作用?
  • ¥15 使用rabbitMQ 消息队列作为url源进行多线程爬取时,总有几个url没有处理的问题。
  • ¥15 Ubuntu在安装序列比对软件STAR时出现报错如何解决
  • ¥50 树莓派安卓APK系统签名
  • ¥65 汇编语言除法溢出问题
  • ¥15 Visual Studio问题
  • ¥20 求一个html代码,有偿
  • ¥100 关于使用MATLAB中copularnd函数的问题