PHP: пропорциональное уменьшение изображения

Фух. Наконец-то появилось свободное время — завершил все заказы по верстке, написал с нуля небольшой веб сервис (о нём я расскажу позже. В конце августа или в начале сентября), а теперь напишу небольшой урок по php. Хотя в дальнейшем я буду публиковать новые уроки по программированию. Буду рассматривать свои «старые» скрипты, а также делиться опытом в «прямом эфире» — т.е. научился чему-либо, попробую научить и вас.

Сегодня я разберу скрипт своего старого музыкального портала, который я написал в далёком 2005 году, когда ещё никто и не мечтал о верстке дивами и все верстали таблицами. =) Тогда наверно и не существовало html-верстальщиков — ибо один человек мог написать с нуля статическую домашнюю страничку и гордиться этим. Следовательно, мой сайт был сверстан таблицами и у меня появилась проблема. Поскольку любой пользователь мог добавить в галерею сайта фотографии, то фотографий в галерее было много и они были разного размера, но фотогалерея сайта была задумана так, чтобы фотографии размещались по 4 штуки на строку и было 5 строк на странице. Естественно, в полный размер фото бы не уместились и появился бы горизонтальный скролл. Тогда я решил написать скрипт, который при загрузке фото на сервер, создавал бы уменьшенную копию фотографии с шириной 150 пикселей, не теряя при этом пропорций фотографии. Забыл сказать, данный скрипт расчитан на jpg изображения т.к. подавляющее большинство фотографий делаются в этом формате.

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

<?php
//Определяем размер фотографии — ширину и высоту
$size=GetImageSize ("photo.jpg");
//Создаём новое изображение из «старого»
$src=ImageCreateFromJPEG ("photo.jpg");
//Берём числовое значение ширины фотографии, которое мы получили в первой строке и записываем это число в переменную
$iw=$size[0];
//Проделываем ту же операцию, что и в предыдущей строке, но только уже с высотой.
$ih=$size[1];
//Ширину фотографии делим на 150 т.к. на выходе мы хотим получить фото шириной в 150 пикселей. В результате получаем коэфициент соотношения ширины оригинала с будущей превьюшкой.
$koe=$iw/150;
//Делим высоту изображения на коэфициент, полученный в предыдущей строке, и округляем число до целого в большую сторону — в результате получаем высоту нового изображения.
$new_h=ceil ($ih/$koe);
//Создаём пустое изображение шириной в 150 пикселей и высотой, которую мы вычислили в предыдущей строке.
$dst=ImageCreateTrueColor (150, $new_h);
//Данная функция копирует прямоугольную часть изображения в другое изображение, плавно интерполируя пикселные значения таким образом, что, в частности, уменьшение размера изображения сохранит его чёткость и яркость.
ImageCopyResampled ($dst, $src, 0, 0, 0, 0, 150, $new_h, $iw, $ih);
//Сохраняем полученное изображение в формате JPG
ImageJPEG ($dst, "small_photo.jpg", 100);
imagedestroy($src);
?>

Пример работы скрипта вы можете посмотреть здесь. Исходное изображение находится тут. Если хотите, то можете уменьшить любое другое изображение. Для этого передайте скрипту адрес изображения в виде http://www.zhitenev.ru/demo/img-resize/?photo=http://site.ru/1.jpg, где «http://site.ru/1.jpg» — путь к изображению.

Вот и всё. Для решения задачи нам потребовалось всего лишь 9 строк кода. Удачного вам кодинга и работающего кода. До следующего поста!

PHP: пропорциональное уменьшение изображения: 93 комментария

  1. Только по моему тут опечатка в строке $src=ImageCreateFromJPEG («photos.jpg»);
    Должно быть $src=ImageCreateFromJPEG («photo.jpg»);

  2. Отличный алгоритм по уменьшению!!! Все понятно, да еще и подробные комментарии к каждой строчке. Переделал твой пример в виде функции для GIF, JPEG, PNG, думал скопировать сюда — мало ли кому пригодится, да не стал — т.к. в коментарии кусок кода, наверное, не даст разместить.

      1. Тогда вот код:

        function resizeImage($source, $newWidth)
        { // start resizeImage()
        $sizeArr=GetImageSize($source);
        //Берём числовое значение ширины фотографии, которое мы получили в первой строке и записываем это число в переменную
        $iw=$sizeArr[0];
        //Проверяем, если размер ширины до которой мы хотим уменьшить ($newWidth), больше размера, загруженного пользователем фото, то уменьшть нет смысла, выход из функции
        if ($newWidth >= $iw) return;
        //Проделываем ту же операцию, что и в предыдущей строке, но только уже с высотой.
        $ih=$sizeArr[1];
        //Ширину фотографии делим на $newWidth т.к. на выходи мы хотим получить фото шириной в $newWidth пикселей. В результате получаем коэфициент соотношения ширины оригинала с будущей превьюшкой.
        $koe=$iw/$newWidth;
        //Делим высоту изображения на коэфициент, полученный в предыдущей строке, и округляем число до целого в большую сторону — в результате получаем высоту нового изображения.
        $new_h=ceil($ih/$koe);
        //Определяем тип, загруженного пользователем изображения 1 = GIF, 2 = JPG, 3 = PNG
        $type=$sizeArr[2];
        //Создаём новое изображение из «старого». Основываясь на типе загруженного изображения пользователем, выбираем соответствующую функцию.
        if ($type==1) $src=imagecreatefromgif($source);
        else
        if ($type==2) $src=imagecreatefromjpeg($source);
        else
        if ($type==3) $src= imagecreatefrompng($source);
        else
        return;
        //Создаём пустое изображение шириной в $newWidth пикселей и высотой, которую мы вычислили в предыдущей строке.
        $dst=ImageCreateTrueColor($newWidth, $new_h);
        //Данная функция копирует прямоугольную часть изображения в другое изображение, плавно интерполируя пикселные значения таким образом, что, в частности, уменьшение размера изображения сохранит его чёткость и яркость.
        ImageCopyResampled($dst, $src, 0, 0, 0, 0, $newWidth, $new_h, ImageSX ($src), ImageSY ($src));
        //Сохраняем полученное изображение в соответствуещем формате GIF, JPG или PNG
        if ($type==1) imagegif($dst, $source);
        else
        if ($type==2) imagejpeg($dst, $source, 100);
        else
        if ($type==3) imagepng($dst, $source, 0);
        else
        return;
        } // end resizeImage()

  3. Спасибо, Илья.
    Искал пол часа в инете эту страницу:) 😀
    Добавьте пожалуйста кэш по типу этого скрипта:

    $image = »; // в переменной $image будет храниться имя файла, который в данный момент обрабатывается

    define(‘CACHE_DIR’,’uploads/copy’); // директория для хранения кеша (она должна уже существовать)
    include(‘funcopy.php’);

    $name = CACHE_DIR.’/’.$image.’.jpg’; // имя превьюшки (последнее «.jpg» — не ошибка!)

    // если кешированный эскиз уже существует, отдать его и завершить работу

    if (file_exists($name))
    {
    header(‘Content-type: image/jpeg’);
    readfile($name);
    exit();
    }

    // иначе — создаём новый эскиз

    ob_start();
    $res = send_thumbnail($image,200,150); // $res — результат создания эскиза (TRUE или FALSE)
    $content = ob_get_contents(); // записываем в $content содержимое эскиза

    if ($res && (@$fp = fopen($name,’wb+’))) // если всё хорошо, создаём файлик с кешем и пишем туда содержимое
    {
    fputs($fp,$content);
    fclose($fp);
    ob_end_flush(); // выводим эскиз
    }else
    {
    @ob_end_clean(); // очищаем буфер и рапортуем об ошибке
    header(‘Content-type: text/html’); // функция для создания preview отправляет заголовок Content-type: image/jpeg, а буферизация вывода заголовки пропускает
    die(‘Could not create preview! Reason: ‘.d_error());
    }

  4. Ура!!!
    всё)
    Прикрутил, можете посмотреть результат:) на моём сайте
    Только осталось решить проблемы с выводом в двиге.

  5. Угу, где в самом центре jquery прокрутка. 😀
    Сейчас осталось оптимизировать под ie и запустить волну регистрации.
    Всем удачи!

  6. Люди а не подскажите как сделать уменьшения изображения перед загрузкой на сервер??

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

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

  8. Только вот… А если изображение было менее 150 пикселей что оно с ним сделает?
    То что мы, вернее Вы 😉 ограничили ширину 150-ю пикселями это хорошо, но вот высота ведь ничем не ограничена?!!! А если кто то возьмёт и попробует загрузить на сервер изображение 200 на 10 000 пикселей? 😕 ❓

    1. Тогда оно уменьшиться до 150 на пропорциональную высоту. Данный скрипт предназначен чтобы уменьшать картинки, но не портить их пропорции.

      На сайте, для которого я делал этого скрипт, было важно чтобы картинки в 4 столбца не растягивали сайт в ширину, а в высоту можно.

  9. Автору статьи большое спасибо ))
    сам работу с картинками в пхп как ни старался — не осилил.
    возникла точь в точь такая же задача как у тебя (за исключением того что я делаю wap сайт) — искал в интернете решение, но лучше чем у тебя не нашел ))
    даже вроде понял немного )

  10. Интересно, а почему в 2005 никто не мечтал о верстке дивами? И почему не было верстальщиков? Может, вы просто мало тогда знали?

    1. Верстальщики были, но подавляющее большинство сайтов было сверстано таблицами. Дивы уже использовали, но многие не знали или не хотели переделывать код своих сайтов только ради того, чтобы странички были написаны другим кодом

  11. Классный урок, сейчас буду разбирать но по описанию все понятно вроде бы.

    Хорошо бы еще работающий пример в архиве. Просто не все программисты есть и те кто учатся на этом.

  12. Все я во всем разобрался. Из того что я находил это самый простой пример пропорционального изменения размера изображения. Автор супер )))) с удовольствием буду следить за блогом.

  13. Спасибо, Илья! Столкнулся с подобной задачей. Много искал инфы на эту тему, но везде либо сложно объясняется, либо непонятно. А в Вашем примере все коротко и ясно. И все работает!

  14. Илья, спасибо, взял на вооружение, а на сколько сложнее сделать скрипт который бы поддерживал и png u gif?

    1. Ответ для Леха: не за что. В принципе не очень сложно, надо сначала определить тип файла, а затем, в зависимости от типа файла, выполнять определённый скрипт. Если сами не сможете разобраться — сообщите, как будет свободная минутка напишу скриптик

  15. зачем в 17 строке вызывать ImageSX и ImageSY, когда данные о ширине и высоте оригинала хранятся в $iw и $ih ??

  16. Странно, скрипт прексасно справляется сшириной, но высоту практически не трогает

  17. Спасибо большое, но не пойму, как выводится изображение? это все поместить в img src=»» или как?

  18. простите! это опять я. а в
    $size=GetImageSize («photo.jpg»);
    //Создаём новое изображение из «старого»
    $src=ImageCreateFromJPEG («photo.jpg»);
    эти строчки указывается адрес изображения?
    у меня ничего не получается(((( может каких-то библиотек не хватает?

      1. Да, там указывается путь к изображению.
        Нужна библиотека gd2 — включите её, раскомментировав строчку в файле php.ini

  19. с png не канает…… 😕 😡 ругается на ImageCreateFromJPEG… нет ли какой-нить универсальной функции, чтоб работала со всеми форматами?

  20. Респект Автору. Все просто и понятно. Оч лего оптимизировать под свои нужды данный код. Разрешения фоток, работа с разными расширениями изображений на основе его проверки… В общем он дал основу, а дальше уж сами. Всё супер, спасибо.

  21. здравствуйте Илья, у меня такой вопрос,если вам не трудно то прошу ответить))
    Мне нужно взять из БД изображение большого размера и вывести на странице уже уменьшенное.
    как это сделать????? зарание благодарен))

      1. Спасибо уже не нужно,узнал что уменьшение «на лету» сильно загружает сайт и может привести к ошибкам((
        Лучше сделать миниатюру и вывести в нужное место.

        1. Именно так. Хотя предлагаю выход из ситуации.
          В базе к каждому файлу даёте параметр — который означает существует ли файл миниатюры или нет. Если миниатюры нет — вы берёте ссылку и создаёте файл миниатюры «на лету», затем записывайте в эту же запись адрес к миниатюре и в следующий раз при надобности просто загружаете готовую миниатюру.

          Как видите — вы обрабатываете каждое изображение лишь однажды, например при добавлении большой фотографии на сервер — вы создаёте миниатюры, а затем используете уже ранее созданные миниатюры не вынуждая сервер каждый раз генерировать их снова

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *