php根据背景图片深浅加水印

最近做到一个项目要实现这样一个功能, 根据上传图片的主色调, 在图片上加水印或文字.

比如上传的图片颜色较深,文字的颜色用浅色标识,如果图片颜色较浅, 则文字颜色用深色标识.

解决方法是:

先确定要加文字的图片区域,遍历每一个像素点, 取得该区域像素点的平均亮度, 根据平均亮度决定文字的颜色. 如果该图片区域的颜色不复杂,只是一个纯色块,就不需要遍历了,只需要获取色块中某个像素点的亮度就可以了.

不建议遍历整张图, 而只是遍历需要加水印的图片文字的区域, 否则会有性能问题.

/**
 * 获取图片某个像素的颜色及亮度
 * @author  church <church_qi@aliyun.com>
 * @date 2017-4-5
 */
class ImgColor
{
    /**
     * RGB格式
     */
    const RGB = 1;

    /**
     * 6位十六进制格式
     */
    const HEX_6_BIT = 2;

    /**
     * 8位十六进制格式
     */
    const HEX_8_BIT = 3;

    /**
     * 打开图片
     * @param  string $img_path 图片路径
     * @return resource           
     */
    public static function openImg($img_path)
    {
        if(!is_file($img_path)) {
            throw new Exception("不存在的图片");
        }

        $info = getimagesize($img_path);

        if(false === $info || (IMAGETYPE_GIF === $info[2] && empty($info['bits']))){
            throw new Exception("非法的图片");
        }

        $img_info = array(
            'width'  => $info[0],
            'height' => $info[1],
            'type'   => image_type_to_extension($info[2], false),
            'mime'   => $info['mime'],
        );

        $fun = "imagecreatefrom{$img_info['type']}";
        $img = $fun($img_path);

        return $img;
    }

    /**
     * 获取某个像素的颜色
     * @param  string $img_path  图片路径
     * @param  integer $x        横坐标
     * @param  integer $y        纵坐标
     * @param  integer $format   格式
     * @return mixed
     */
    public static function getColor($img_path = '', $x, $y, $format = self::HEX_8_BIT)
    {
        static $img;

        $getRgb = function($img) use ($x, $y) {
            $rgb = imagecolorat($img, $x, $y);
            $r = ($rgb >> 16) & 0xFF;
            $g = ($rgb >> 8) & 0xFF;
            $b = $rgb & 0xFF;
            return [$r, $g, $b];
        };

        if (!(isset($img) && is_resource($img))) {
            $img = self::openImg($img_path);
        }

        return self::rgbToFormat($getRgb($img), $format);

    }

    /**
     * 获取某个像素的亮度 (范围为0~255, 越小越深)
     * 算法参考: https://www.w3.org/TR/AERT#color-contrast
     * 
     * @param  string $img_path  图片路径
     * @param  integer $x        横坐标
     * @param  integer $y        纵坐标
     * @return double           
     */
    public static function getBrightnessOfPixel($img_path = '', $x, $y)
    {
        list($r, $g, $b) = self::getColor($img_path, $x, $y, self::RGB);
        $g = $r * 0.299 + $g * 0.587 + $b * 0.114;

        return $g;
    }

    /**
     * 把rgb格式转换成其它格式
     * @param  array  $rgb     
     * @param  integer $format 格式
     * @return string         
     */
    public static function rgbToFormat($rgb, $format)
    {
        list($r, $g, $b) = $rgb;
        $result = '#';

        switch ($format) {
            case self::RGB:
                return $rgb;
                break;
            case self::HEX_6_BIT:
                $result .= str_pad(dechex($r), 2, '0', STR_PAD_LEFT);
                $result .= str_pad(dechex($g), 2, '0', STR_PAD_LEFT);
                $result .= str_pad(dechex($b), 2, '0', STR_PAD_LEFT);
                return $result;
                break;
            case self::HEX_8_BIT:
                $result .= 'ff';
                $result .= str_pad(dechex($r), 2, '0', STR_PAD_LEFT);
                $result .= str_pad(dechex($g), 2, '0', STR_PAD_LEFT);
                $result .= str_pad(dechex($b), 2, '0', STR_PAD_LEFT);
                return $result;
                break;
        }

    }

}

亮度的范围为0~255, 越小越深, 越大越浅; 判断时可以取中位, 大于125就算浅,小于就算深.

require './ImgColor.php';

$img_path = './test.png';

$brightness = 0;
for ($i = 0; $i < 100; $i++) {
    for ($j = 0; $j < 100; $j++) {
        $brightness += ImgColor::getBrightnessOfPixel($img_path, $i, $j);
    }
}

$brightness /= 10000;

$font_color = '';

$brightness = $brightness > 125 ? '较浅' : '较深';

//若背景色较浅, 水印文字颜色设置为黑色, 反之则设置为白色
$font_color = $brightness == '较浅' ? '#00000000' : '#ffffffff';
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值