Pull to refresh

Реализация эффекта Philips Ambilight в превью изображений

Reading time16 min
Views3.9K
Вчера в топике «Модификация изображений для сайта, или какие бывают превьюшки» в комментариях diGreez предложил, как мне показалось, очень интересный способ организации превьюшек изображений. Реализовал на PHP функцию, которая занимается созданием таких превьюшек.
Функция документирована комментариями.

Copy Source | Copy HTML<br/>// функция создаёт "миниатюру" изображения сохраняя пропорции<br/>// и обрамляет неиспользуемое пространство в стиле Philips Ambilight<br/>// Входные параметры:<br/>//      $image_from         - имя файла исходного изображения<br/>//      $image_to           - имя файла результирующего изображения<br/>//      $width              - желаемая ширина результирующей "миниатюры"<br/>//      $height             - желаемая высота результирующей "миниатюры"<br/>//      $padding            - минимальная рамка в пикселях (по умолчанию = 5)<br/>//      $dest_image_type    - тип изображения для сохранения (по умолчанию JPG):<br/>//          2 - JPG<br/>//          3 - PNG<br/>// Возвращает:<br/>//      TRUE   - в случае успеха<br/>//      FALSE  - в случае неудачи<br/>function aidsoid_resize_image($image_from, $image_to, $width=200, $height=200, $padding=5, $dest_image_type=2) {<br/>    $image_vars = getimagesize($image_from);<br/>    if (!$image_vars) {<br/>        return FALSE;<br/>    }<br/>    $src_width = $image_vars[ 0];<br/>    $src_height = $image_vars[1];<br/>    $src_type = $image_vars[2];<br/>    if (($src_type != IMAGETYPE_JPEG) and ($src_type != IMAGETYPE_PNG)) {<br/>        return FALSE;<br/>    }<br/> <br/>    switch ($src_type) {<br/>    case IMAGETYPE_JPEG:<br/>        $src_image = imagecreatefromjpeg($image_from);<br/>        break;<br/>    case IMAGETYPE_PNG:<br/>        $src_image = imagecreatefrompng($image_from);<br/>        break;<br/>    default:<br/>        return FALSE;<br/>        break;<br/>    }<br/>    if (!$src_image) return FALSE;<br/> <br/>    // создаем задний фон для нового изображения<br/>    $dest_image = imagecreatetruecolor($width, $height);<br/> <br/>    // копируем из исходного изображения в фон и растягиваем без соблюдения пропорций<br/>    $result = imagecopyresized($dest_image, $src_image,  0,  0,  0,  0, $width, $height, $src_width, $src_height);<br/>    if (!$result) return FALSE;<br/> <br/>    // применяем к фону размытие<br/>    for ($i= 0; $i<=100; $i++) {<br/>        $result = imagefilter($dest_image, IMG_FILTER_SMOOTH, 6);<br/>        if (!$result) return FALSE;<br/>    }<br/> <br/>    // деление на ноль - плохая идея<br/>    if ( ($src_width ==  0) or ($src_height ==  0) ) {<br/>        return FALSE;<br/>    }<br/> <br/>    // вычисляем масштабный коэффициент<br/>    $ratio = min( ($width-2*$padding)/$src_width , ($height-2*$padding)/$src_height );<br/> <br/>    // вычисляем новые размеры изображения<br/>    $new_width = $ratio * $src_width;<br/>    $new_height = $ratio * $src_height;<br/> <br/>    // если новая высота или новая длина больше оригинальных,<br/>    // то это значит, что изображение будет растянуто, не нужно допускать этого,<br/>    // в этом случае оставим оригинальное изображение без изменения размеров<br/>    if ( ($new_width >= $src_width) or ($new_height >= $src_height) ) {<br/>        $new_width = $src_width;<br/>        $new_height = $src_height;<br/>    }<br/> <br/>    // скопируем поверх фона получившееся изображение<br/>    $result = imagecopyresampled($dest_image, $src_image, round(($width-$new_width)/2), round(($height-$new_height)/2),  0,  0, $new_width, $new_height, $src_width, $src_height);<br/>    if (!$result) return FALSE;<br/> <br/>    // сохраняем на носитель<br/>    switch ($dest_image_type) {<br/>    case IMAGETYPE_JPEG: // качество изображения 100<br/>        $result = imagejpeg($dest_image, $image_to, 100);<br/>        break;<br/>    case IMAGETYPE_PNG: // максимальный уровень сжатия 9<br/>        $result = imagepng($dest_image, $image_to, 9);<br/>        break;<br/>    default:<br/>        return FALSE;<br/>        break;<br/>    }<br/>    if (!$result) return FALSE;<br/>    chmod($image_to, 0777);<br/> <br/>    return TRUE;<br/>} <br/>


Пример использования:
Copy Source | Copy HTML<br/>aidsoid_resize_image("image.jpg", "i/news/image-mini.jpg", 200, 200, 5, 2); <br/>


Результат работы функции:
imageimageimage

Update. Версия 2: Еще одна версия с другим алгоритмом. Для работы этой версии требуется функция pixelate, которая была найдена мной на просторах интернета, она позволяет пикселизовать изображение. Принцип работы второй версии следующий: находим средние значения цветов каждых 5 пикселей на границах изображения и «размазываем» эти цвета до края рамки. Затем для смягчения всё это заблюривается.

Copy Source | Copy HTML<br/>function pixelate(&$image) {<br/>    $imagex = imagesx($image);<br/>    $imagey = imagesy($image);<br/>    $blocksize = 5;<br/> <br/>    for ($x =  0; $x < $imagex; $x += $blocksize) {<br/>        for ($y =  0; $y < $imagey; $y += $blocksize) {<br/>            // get the pixel colour at the top-left of the square<br/>            $thiscol = imagecolorat($image, $x, $y);<br/> <br/>            // set the new red, green, and blue values to 0<br/>            $newr =  0;<br/>            $newg =  0;<br/>            $newb =  0;<br/> <br/>            // create an empty array for the colours<br/>            $colours = array();<br/> <br/>            // cycle through each pixel in the block<br/>            for ($k = $x; $k < $x + $blocksize; ++$k) {<br/>                for ($l = $y; $l < $y + $blocksize; ++$l) {<br/>                    // if we are outside the valid bounds of the image, use a safe colour<br/>                    if ($k <  0) { $colours[] = $thiscol; continue; }<br/>                    if ($k >= $imagex) { $colours[] = $thiscol; continue; }<br/>                    if ($l <  0) { $colours[] = $thiscol; continue; }<br/>                    if ($l >= $imagey) { $colours[] = $thiscol; continue; }<br/> <br/>                    // if not outside the image bounds, get the colour at this pixel<br/>                    $colours[] = imagecolorat($image, $k, $l);<br/>                }<br/>            }<br/> <br/>            // cycle through all the colours we can use for sampling<br/>            foreach($colours as $colour) {<br/>                // add their red, green, and blue values to our master numbers<br/>                $newr += ($colour >> 16) & 0xFF;<br/>                $newg += ($colour >> 8) & 0xFF;<br/>                $newb += $colour & 0xFF;<br/>            }<br/> <br/>            // now divide the master numbers by the number of valid samples to get an average<br/>            $numelements = count($colours);<br/>            $newr /= $numelements;<br/>            $newg /= $numelements;<br/>            $newb /= $numelements;<br/> <br/>            // and use the new numbers as our colour<br/>            $newcol = imagecolorallocate($image, $newr, $newg, $newb);<br/>            imagefilledrectangle($image, $x, $y, $x + $blocksize - 1, $y + $blocksize - 1, $newcol);<br/>        }<br/>    }<br/>}<br/> <br/>// функция создаёт "миниатюру" изображения сохраняя пропорции<br/>// и обрамляет неиспользуемое пространство в стиле Philips Ambilight<br/>// Входные параметры:<br/>//      $image_from         - имя файла исходного изображения<br/>//      $image_to           - имя файла результирующего изображения<br/>//      $width              - желаемая ширина результирующей "миниатюры"<br/>//      $height             - желаемая высота результирующей "миниатюры"<br/>//      $padding            - минимальная рамка в пикселях (по умолчанию = 5)<br/>//      $dest_image_type    - тип изображения для сохранения (по умолчанию JPG):<br/>//          2 - JPG<br/>//          3 - PNG<br/>// Возвращает:<br/>//      TRUE   - в случае успеха<br/>//      FALSE  - в случае неудачи<br/>function aidsoid_resize_image($image_from, $image_to, $width=200, $height=200, $padding=5, $dest_image_type=2) {<br/>    $image_vars = getimagesize($image_from);<br/>    if (!$image_vars) {<br/>        return FALSE;<br/>    }<br/>    $src_width = $image_vars[ 0];<br/>    $src_height = $image_vars[1];<br/>    $src_type = $image_vars[2];<br/>    // деление на ноль - плохая идея<br/>    if ( ($src_width ==  0) or ($src_height ==  0) ) {<br/>        return FALSE;<br/>    }<br/>    // проверяем тип файла<br/>    if (($src_type != IMAGETYPE_JPEG) and ($src_type != IMAGETYPE_PNG)) {<br/>        return FALSE;<br/>    }<br/> <br/>    switch ($src_type) {<br/>    case IMAGETYPE_JPEG:<br/>        $src_image = imagecreatefromjpeg($image_from);<br/>        break;<br/>    case IMAGETYPE_PNG:<br/>        $src_image = imagecreatefrompng($image_from);<br/>        break;<br/>    default:<br/>        return FALSE;<br/>        break;<br/>    }<br/>    if (!$src_image) return FALSE;<br/> <br/>    // создаем задний фон для нового изображения<br/>    $dest_image = imagecreatetruecolor($width, $height);<br/> <br/>    // копируем из исходного изображения в фон и растягиваем без соблюдения пропорций<br/>    $result = imagecopyresized($dest_image, $src_image,  0,  0,  0,  0, $width, $height, $src_width, $src_height);<br/>    if (!$result) return FALSE;<br/> <br/>    // вычисляем масштабный коэффициент<br/>    $ratio = min( ($width-2*$padding)/$src_width , ($height-2*$padding)/$src_height );<br/> <br/>    // вычисляем новые размеры изображения<br/>    $new_width = $ratio * $src_width;<br/>    $new_height = $ratio * $src_height;<br/> <br/>    // если новая высота или новая длина больше оригинальных,<br/>    // то это значит, что изображение будет растянуто, не нужно допускать этого,<br/>    // в этом случае оставим оригинальное изображение без изменения размеров<br/>    if ( ($new_width >= $src_width) or ($new_height >= $src_height) ) {<br/>        $new_width = $src_width;<br/>        $new_height = $src_height;<br/>    }<br/> <br/>    // копируем из исходного изображения в фон с соблюдением пропорций<br/>    $result = imagecopyresampled($dest_image, $src_image, round(($width-$new_width)/2), round(($height-$new_height)/2),  0,  0, $new_width, $new_height, $src_width, $src_height);<br/>    if (!$result) return FALSE;<br/> <br/>    // пикселизуем фон<br/>    pixelate($dest_image);<br/> <br/>    $tmp_x = round(($width-$new_width)/2);<br/>    $tmp_y = round(($height-$new_height)/2);<br/>    // размазываем вверх<br/>    $result = imagecopyresized($dest_image, $dest_image, $tmp_x,  0, $tmp_x, $tmp_y, $new_width, $tmp_y, $new_width, 1);<br/>    if (!$result) return FALSE;<br/>    // размазываем вниз<br/>    $result = imagecopyresized($dest_image, $dest_image, $tmp_x, $tmp_y+$new_height, $tmp_x, $tmp_y+$new_height-1, $new_width, $tmp_y, $new_width, 1);<br/>    if (!$result) return FALSE;<br/>    // размазываем влево<br/>    $result = imagecopyresized($dest_image, $dest_image,  0, $tmp_y, $tmp_x, $tmp_y, $tmp_x, $new_height, 1, $new_height);<br/>    if (!$result) return FALSE;<br/>    // размазываем вправо<br/>    $result = imagecopyresized($dest_image, $dest_image, $tmp_x+$new_width, $tmp_y, $tmp_x+$new_width-1, $tmp_y, $tmp_x, $new_height, 1, $new_height);<br/>    if (!$result) return FALSE;<br/> <br/>    // размываем фон<br/>    for ($i= 0; $i<=50; $i++) {<br/>        $result = imagefilter($dest_image, IMG_FILTER_SMOOTH, 6);<br/>        if (!$result) return FALSE;<br/>    }<br/> <br/>    // скопируем поверх фона получившееся изображение<br/>    $result = imagecopyresampled($dest_image, $src_image, round(($width-$new_width)/2), round(($height-$new_height)/2),  0,  0, $new_width, $new_height, $src_width, $src_height);<br/>    if (!$result) return FALSE;<br/> <br/>    // сохраняем на носитель<br/>    switch ($dest_image_type) {<br/>    case IMAGETYPE_JPEG: // качество изображения 100<br/>        $result = imagejpeg($dest_image, $image_to, 100);<br/>        break;<br/>    case IMAGETYPE_PNG: // максимальный уровень сжатия 9<br/>        $result = imagepng($dest_image, $image_to, 9);<br/>        break;<br/>    default:<br/>        return FALSE;<br/>        break;<br/>    }<br/>    if (!$result) return FALSE;<br/>    chmod($image_to, 0777);<br/> <br/>    return TRUE;<br/>} <br/>


А вот результат работы второй версии:
imageimageimage
Tags:
Hubs:
+63
Comments62

Articles