Конвертация JPG в PNG на PHP (с прозрачным фоном)


Недавно столкнулся с ситуацией когда мне необходимо было конвертировать jpg в png, при этом нужно было убрать фон. Изображений, которые необходимо обработать, у меня около 2-ух тысяч. Естественно вариант с фотошопом и ящиком энергетиков сразу отпадает. Сделать это все необходимо в интернет-магазине.

Первое что приходит в голову это собрать все изображения в массив (проще всего функцией scandir()), затем пробежаться по массиву и применить к каждому элементу некую функцию.

Дело осталось за малым – написать эту функцию конвертации JPG в PNG.

Мы уже разбирали конвертацию PNG в JPG. Там дело обстояло намного проще. Сейчас поговорим об обратном.

Итак, приступим!

Я посмотрел в PHP библиотеку GD, а именно функцию imagefill(), но это было не совсем то, что мне нужно. Эта функция заполняет только точный цвет, а в JPG можно найти миллионы цветов, ещё есть и тот фактор, что есть много оттенков, которые человеческий глаз воспринимают одинаково.

Необходимо что-то, где можно указать точность порога цвета, и этот диапазон программа бы заливала.

Для решения этой проблемы пришлось облазить много пендосовских форумов, блогов и порталов.

В результате мне всё-таки удалось собрать по крупицам ту самую функцию для которая могла бы конвертировать JPG в PNG с прозрачностью. Я накидал небольшой класс для этой задачи. Работает он конечно не идеально, но тем не менее, в моём случае, для интернет-магазина её оказалось вполне достаточно.

При создании объекта конструктора «transparaizer», в него необходимо передать 3 параметра:

  1. Путь к файлу на сервере
  2. Цвет фона (который необходимо заменить на прозрачный)
  3. Точность порога перехода от одного цвета в другой.

Стоит учесть, что чем выше точность порога, тем больше ресурсов потребляет программа, но более качественнее получаем изображение на выходе.

Ниже приведён код примера работы этого примера.

<?php

class transparaizer
{
    /**
     * Цвет который необходимо убрать (фон)
     */
    private $colour = "FFFFFF";

    /**
     * Чем будем заменять 
     */
    private $replace = "FF00FF";

    /**
     * Точность разницы в цвета, для замены
     */
    private $threshold = 145;

    /**
     * Собстна сам файл
     */
    private $image = "";

    /*
    *   Вычисляем разницу в цветах
    */
    private function colordiff($R1, $G1, $B1, $R2, $G2, $B2)
    {
        $RD = $R1 - $R2;
        $GD = $G1 - $G2;
        $BD = $B1 - $B2;
        return sqrt($RD * $RD + $GD * $GD + $BD * $BD);
    }

    /*
    *   Конвертируем html цвет в rgb
    */
    private function html2rgb($input)
    {
        $input = ($input[0] == "#") ? sub_str($input, 1, 6) : sub_str($input, 0, 6);
        return array(
            'r' => hexdec(sub_str($input, 0, 2)),
            'g' => hexdec(sub_str($input, 2, 2)),
            'b' => hexdec(sub_str($input, 4, 2)));
    }

    /*
    *   Конструктор класса
    */
    public function __construct($image, $colour, $threshold, $replace = null)
    {
        if (!file_exists($image))
            throw new Exception("Could not find file {$image} for processing.");
        $this->image = $image;
        $this->colour = $colour;
        $this->threshold = (int)$threshold;
        if ($replace)
            $this->replace = $replace;
    }

    /*
    *  Основная функция, которая все делает...
    */
    public function output()
    {
        header("Content-Type: image/png");

        list($w, $h, $type, $attr) = getimagesize($this->image);
        
     //$img = imagecreatefromjpeg($this->image);
     $type = getimagesize($this->image);
           switch ($type['mime']) {
              case "image/jpeg":
              $img = imageCreateFromJPEG($this->image);
              break;
 
              case "image/gif":
              $img = imageCreateFromGIF($this->image);
              break;
 
              case "image/png":
              $img = imageCreateFromPNG($this->image);
              break;
   
              default:
              die("Тип файла не распознан - " . $type['mime']);
              }

        list($r_r, $r_g, $r_b) = array_values($this->html2rgb($this->replace));
        $replace = imagecolorallocate($img, $r_r, $r_g, $r_b);

        list($f_r, $f_g, $f_b) = array_values($this->html2rgb($this->colour));

        for ($y = 0; $y < $h; $y++) {
            for ($x = 0; $x < $w; $x++) {
                $color = array_values(imagecolorsforindex($img, imagecolorat($img, $x, $y)));
                list($r, $g, $b, $a) = array_values($color);

                $color_diff = $this->colordiff($r, $g, $b, $f_r, $f_g, $f_b);

                if ($color_diff <= $this->threshold) {
                    imagefilledrectangle($img, $x, $y, $x, $y, $replace);
                } else {
                    break;
                }
            }

            for ($x = $w - 1; $x >= 0; $x--) {
                $color = array_values(imagecolorsforindex($img, imagecolorat($img, $x, $y)));
                list($r, $g, $b, $a) = array_values($color);
                $color_diff = $this->colordiff($r, $g, $b, $f_r, $f_g, $f_b);
                if ($color_diff <= $this->threshold) {
                    imagefilledrectangle($img, $x, $y, $x, $y, $replace);
                } else {
                    break;
                }
            }
        }

        // Готово  сохраняю при необходимости во внешний файл
        imagecolortransparent($img, $replace);
        imagepng($img);
    }
}

if (isset($_POST["submit"]) && isset($_POST["colour"]) && isset($_POST["threshold"]) &&
    isset($_FILES["img"])) {
    if ($_FILES["img"]["type"] != "image/jpeg")
        throw new Exception("File must be of JPEG format");
    $t = new transparaizer($_FILES["img"]["tmp_name"], $_POST["colour"], $_POST["threshold"]);
    $t->output();
} else {
?>
<form method="post" action="" enctype="multipart/form-data"> 
<p>Выберите файл: JPEG/JPG:<br /> 
<input type="file" name="img" accept="image/jpeg" /></p> 
<p>Фоновый цвет (который убираем):<br /> 
#<input type="text" name="colour" value="FFFFFF" /></p> 
<p>Точность границ:<br /> 
<input type="text" name="threshold" value="145" /></p> 
<p><input type="submit" name="submit" value="Transparentize" /></p> 
</form> 
<?php
}
?>
 


Тэги:

Комментарии: 6

Прокомментировать »

 
 
Alex
23.07.2013
 

А если исходное изображение gif, тогда не сработает...

Lavrik
23.07.2013
 

Для этого, вмести 74 строчки нужно поставить:

      $type = getimagesize($this->image);
 
      switch ($type['mime']) {
         case "image/jpeg":
         $img = imageCreateFromJPEG($this->image);
         break;
 
         case "image/gif":
         $img = imageCreateFromGIF($this->image);
         break;
 
         case "image/png":
         $img = imageCreateFromPNG($this->image);
         break;
 
         default:
         die("Тип файла не распознан - " . $type['mime']);
         }

Lavrik
24.07.2013
 

Поправил код так, что-бы он был форматно-независим...

Игорь
10.09.2014
 

Lavrik, не работает скрипт. 1) Не подставляется формат - просто 2) и не понятно куда и как можно сохранить. 3) Хотелось бы возможность выбора размера. ["GD Version"]=> string(27) "bundled (2.0.34 compatible)" и ["GD Version"]=> string(26) "bundled (2.1.0 compatible)"

Игорь
10.09.2014
 

Все работает, ошибка была в sub_str. Но, я не понял как в переменную $replace занести прозрачность то?) И с большими файлами похоже не очень работает..

nick
15.10.2016
 

Открываю файл JPEG, жму кнопку и вылетает надпись: изображение не может быть показано, так.как содержит ошибки. В коде исправляю строчку imagepng($img); на imagepng($img,'new.png'); Но файл не сохраняется. В общем не работает ваш код =( PHP 5.5

 

Прокомментировать

 
 
Сообщение *
 
Проверочный код *
 
 
 
Яндекс.Метрика