<
  • Главная
Статьи

PHP-клас для ресайз зображень

  1. функціональність
  2. Реалізація
  3. Вписування в рамки
  4. Стиснення зображення по ширині
  5. Стиснення зображення по висоті
  6. Crop (довільна обрізка зображень)
  7. Обрізка квадратної області зображення
  8. «Розумне» створення мініатюр
  9. збереження зображення
  10. Використання

Увага

Увага! Стаття застаріла. З'явилася нова версія продукту. По ній також написана стаття, створена документація і написані демо. Ця стаття може використовуватися лише в освітніх цілях. Прочитати про нову версію продукту ви можете, перейшовши по засланні .

Завдання масштабування і обрізання зображень в інтернеті зустрічається дуже часто. Це і соціальні мережі, і фотохостинги, де з завантаженого зображення необхідно створити мініатюру. Проте кожного разу писати php-скрипти для ресайз під якусь конкретну задачу або замовлення - утомливо. Саме тому я написав свій клас на php, що дозволяє дуже зручно змінювати розміри зображень і виконувати їх обрізку. У цій статті я розкажи про його можливості і спробую описати всі методи масштабування і кропа (обрізки) зображень. Якщо вам нецікаво або непотрібно знати, як все влаштовано і працює, то варто звернути увагу лише на використання класу, а сам исходник знайдете в кінці статті. Якщо ж ви більше допитливі і хочете повністю розуміти, як саме відбувається масштабування, то читаємо статтю далі.

Увага! У статті не будуть розглянуті базові принципи ООП-програмування. Стаття про ресайз зображень, тому, перш я рекомендую ознайомитися з темою об'єктно-орієнтованого програмування на PHP.

функціональність

Перш за все, необхідно визначитися з тим, що повинен вміти робити наш клас. Я довго вивчав різні необхідні методи зміни розмірів зображень, згадував, які мені реально стали в нагоді в житті, і в кінці кінців мій клас знайшов наступну функціональність:

  • вписування зображень в зазначені рамки;
  • стиснення за вказаною ширині;
  • стиснення за вказаною висоті;
  • обрізка довільної області зображення;
  • обрізка квадратної області зображення;
  • "Розумне" створення мініатюр.

Реалізація

Отже, приступимо до написання каркаса самого класу і деяких допоміжних функцій.

Конструктор в якості аргументу приймає адресу файлу, після чого перевіряє його на існування. Функція setType ($ file) встановлює в приватний член класу type тип зображення. Функція, зрозуміло, приватна, бо ззовні класу використовуватися не буде. Вона дізнається mime-тип файлу і якщо файл є зображенням, в поле type записує його тип.

Після цього в конструкторі викликається функція openImage ($ file). Вона створює на основі файлу ідентифікатор зображення і записує його в член класу - image. Ну і нарешті, setSize () зберігає розміри зображення у відповідних полях. Всі функції також приватності.

Тепер ми можемо створити екземпляр класу acResizeImage:

Природно, зображення image.jpg має існувати.

Після того, як створений екземпляр класу, ми можемо їм оперувати (змінювати розміри зображення, обрізати його і т. Д.). Отже, приступимо.

Вписування в рамки

Припустимо, у нас є фотоальбом і при кліці на мініатюру в віконці повинно з'являтися велика фото. Але ж розміри віконця обмежені. Скажімо, ми хочемо, щоб воно було не більше, ніж 800 × 800. Значить, всі файли в фотоальбом фотографії повинні бути вписані в ці рамки. Зрозуміло, фото буде скорочуватися пропорційно.
Припустимо, у нас є фотоальбом і при кліці на мініатюру в віконці повинно з'являтися велика фото
Для подібного ресайз слід викликати наступну функцію класу:

Ось сам код функції resize () (додайте його в клас):

Зауважте, обидва параметри, прийняті функцією, є обов'язковими. Пізніше поясню, навіщо це потрібно.

У масив $ newSize ми записуємо нові розміри зображення. Залежно від параметрів, переданих у функцію, нові розміри зображення повертаються різними функціями:

  • getSizeByFramework ($ width, $ height);
  • getSizeByWidth ($ width);
  • getSizeByHeight ($ height).

Якщо передані обидва параметри (і ширина, і висота), то майбутні розміри картинки нам поверне функція getSizeByFramework (). Це означає, що зображення необхідно вписати в зазначені рамки.
Ось код допоміжної приватній функції:

Функція повертає пропорційно змінені розміри вписаного в рамки зображення. Але повернемося назад до функції resize (). Після того, як нові розміри картинки отримані, на їх основі створюється нове порожнє зображення $ newImage, після чого викликається функція:

Вона-то і копіює масштабувати зображення на нове ($ newImage).

Увага, існує ще одна функція - imagecopyresized (). Вона приймає ті ж параметри, але стискає зображення без згладжування. Я не рекомендую її використовувати.

Ну і нарешті, останні 3 рядки перезаписують вихідне зображення на нове, зберігають нові розміри і (!) Повертають поточний екземпляр класу (про це ми поговоримо пізніше):

Стиснення зображення по ширині

Згадайте аву «вконтакте» ... Ви завантажуєте фото і воно завжди виходить однаковим по ширині, а висота різна, залежно від розмірів вихідного зображення. Повернемося знову до функції resize () і подивимося, що станеться, якщо в функцію передати тільки ширину:

В даному випадку нові розміри зображення нам поверне функція getSizeByWidth ($ width), яка вважає нові розміри зображення, стискаючи картинку пропорційно по ширині.
В даному випадку нові розміри зображення нам поверне функція getSizeByWidth ($ width), яка вважає нові розміри зображення, стискаючи картинку пропорційно по ширині
Додайте в клас ще одну приватну функцію:

Далі все відбувається так само, як і в випадку з вписуванням в рамки - створюється порожній зображення, на нього копіюється масштабувати оригінал, фото і розміри перезаписувати на нові, і в програму повертається поточний об'єкт.

Стиснення зображення по висоті

Завдання аналогічна попередній, але стискається фото, підганяючи вже під висоту:

Розміри вираховуються наступною функцією, яку також не забуваємо додати в клас:
Розміри вираховуються наступною функцією, яку також не забуваємо додати в клас:

Подальші дії в функції resize () аналогічні попереднім двом випадкам.

Crop (довільна обрізка зображень)

Часто потрібно вирізати з вихідного зображення будь-яку область. Для цього реалізуємо функцію crop (). Принцип її роботи прекрасно ілюструє наступне зображення:
Часто потрібно вирізати з вихідного зображення будь-яку область
X0, Y 0 - верхні ліві координати область, що буде. Width, height - її, відповідно, ширина і висота.

Використовується наш кроп наступним чином:

В цьому випадку з вихідного зображення буде вирізана область 500 × 500 px., Починаючи з координати (30, 40).

Ось сама функція (також додаємо її в клас):

Як видно, всі параметри необов'язкові. Так, якщо не передати точки початку обрізки, то це буде точка (0, 0). Повідомити про свої координати, що знаходяться за межами фото, також не вийде. Якщо ширина і висота такі, що вирізати область виходить за межі вихідного зображення, вирізана буде максимально можлива область. Функція cropSave ($ x0, $ y0, $ w, $ h) безпосередньо вирізає необхідну область і повертає поточний об'єкт класу. Ось її код:

Як і у випадку з ресайз, зберігається нове зображення, розміри і повертається поточний об'єкт.

Обрізка квадратної області зображення

Згадаймо назад "вконтакте". Ава у нас може бути прямокутної, але мініатюри поруч з коментарями, зрозуміло, квадратні. Причому, яку саме область оригінальної Ави відображати на мініатюрі, вибираємо ми самі. Тому, до свого класу я додав окремий випадок кропа - квадратний кроп. Його-то зараз і опишемо.

До речі! У наступних статтях ми обов'язково опишемо, як за допомогою цього класу і JavaScript реалізувати такий же принцип обрізки Ави, як «вконтакте».
До речі
На відміну від минулого функції, в цю можна передати лише три параметри, які, як і раніше, все необов'язкові.

Приклад використання:

Перші два параметри - координати верхнього лівого кута область, що буде, а третій параметр - сторона самої квадратної області. Як не дивно, але квадратний кроп було значно важче реалізувати. Уявіть, що в функцію ми не передали жодного параметра. Що ж тоді робити? Я вирішив, що в даному випадку потрібно вирізати максимально велику квадратну область, що знаходиться в центрі зображення. Приблизно ось так:
Перші два параметри - координати верхнього лівого кута область, що буде, а третій параметр - сторона самої квадратної області
Якщо ж вказані координати верхнього лівого кута, але не вказана сторона квадратної області, то функція виріже максимальну квадратну область з вихідного зображення. Виглядає це так:

Це нюанси наклали деякі складності при написанні функції квадратного кропа і тепер вона виглядає так:

Зверніть увагу, в кінці викликається вже відома нам функція збереження потрібно обрізати:

Ось тільки ширина і висота вирізуваного зображення рівні однієї величиною - стороні квадрата. Ця функція поверне поточний екземпляр класу.

«Розумне» створення мініатюр

Із заявленого функціоналу залишилося описати лише створення мініатюр. Спробую розповісти, в чому ж полягає сама задача. Отже, припустимо, ми на своєму сайті вирішили реалізувати фотоальбом. Мініатюри в альбомах будуть розташовані у вигляді сітки. У чому ж проблема? - запитаєте ви, - Адже ми вміємо вже масштабувати зображення! Тоді дивіться, як у нас буде виглядати «таблиця» мініатюр в альбомах, при класичному ресайз:
Із заявленого функціоналу залишилося описати лише створення мініатюр
Не дуже, правда? Зображення бувають різні - горизонтальні, вертикальні, квадратні і вже дуже химерні (наприклад, 1000 × 150). Що тільки користувач не завантажить! ..

Так, звичайно ж, можна стискати всі фотографії для мініатюр, скажімо, по ширині. В такому випадку альбом стане набагато миловидна, але висота превьюшек буде різною. Все-одно виходить не дуже. Що ж зробимо ми? Ми будемо намагатися «заповнити» область одного осередку таблиці по-максимуму. Так, частина зображення видно не буде, але для мініатюр це не критично. Більш того, наша функція буде ще розумнішими - якщо фото занадто сильно витягнуте по одній зі сторін, то ми спробуємо його масштабувати так, щоб в область мініатюри потрапила найбільша частина зображення. Розглянемо все на прикладах:

Відразу домовимося - мініатюри будуть відображатися в сітці 3 × 3, а розміри кожного осередку співвідноситися як 4 × 3. Нехай для прикладу розмір осередку, яку будемо намагатися максимально заповнити прев'юшки, буде дорівнює 120 × 90.

Зрозуміло, що фото з пропорціями 4 × 3 і так заповнить всю осередок. Цей приклад розглядати не будемо. Розглянемо спершу 2 фото: 16 × 9 і 9 × 16. Ось як це буде виглядати:
Зрозуміло, що фото з пропорціями 4 × 3 і так заповнить всю осередок
Частини картинок, які зображені більш тьмяно, видно не будуть - вони не помістяться в клітинку, зате вся осередок буде повністю заповнена і лише незначна частина зображення залишиться "за кадром". Нас це цілком влаштовує.

Але що, якщо фото сильно витягнуте? Вийде, що більша частина зображення не видно, а це нас уже не влаштовує, адже часто не вийде навіть зрозуміти, що зображено на фотографії. Тут доведеться йти на "поступки", заповнюючи в повному обсязі осередок, зате зберігаючи велику частину зображення на увазі. Трохи пізніше ми поговоримо про деяке коефіцієнті. Зараз же скажу, що цей коефіцієнт показує, яка частка зображення може бути не видно на мініатюрі. Скажімо, якщо він дорівнює двом, то в тому випадку, коли після стиснення по меншій стороні, велика сторона більш ніж в 2 рази перевищує відповідну сторону осередки, будемо трохи жертвувати "заполненностью" рамки, зменшуючи більшу сторону, до 2 * сторона_ячейкі px.

Покажу на прикладі:
Покажу на прикладі:   У першому випадку менше половини зображення на увазі
У першому випадку менше половини зображення на увазі. А в другому випадку невелика область осередку залишається незаповненою, але цим ми жертвуємо. Варто зауважити, що алгоритм створення мініатюр у мене написано таким чином, що осередок не може бути заповненою менш ніж на половину, крім, зрозуміло, тих випадків, коли вихідне зображення є меншою ніж елементи таблиці.

Якщо картинка ще більш витягнута і одна з її сторін перевищує відповідну сторону рамки більш ніж в 2 * коефіцієнт раз, то зменшуємо цю сторону рівно в 2 рази, але так, щоб осередок не опинилася заповненої менш ніж на половину.

За допомогою цього механізму таблиця з фото, розташована вище, буде виглядати наступним чином:
За допомогою цього механізму таблиця з фото, розташована вище, буде виглядати наступним чином:   Чи не правда - набагато краще
Чи не правда - набагато краще?

Створюємо мініатюру наступним чином:

Перші 2 параметра - розміри рамки, яку необхідно заповнити. Третій параметр - той самий коефіцієнт (за замовчуванням дорівнює двом).

Додаємо в клас функцію:

У даній функції необов'язковим параметром є лише коефіцієнт. Як і при ресайз, але вже за допомогою функції getSizeByThumbnail (), отримуємо нові розміри зображення. Подальші дії абсолютно аналогічні.

Ось код функції getSizeByThumbnail ():

Код дуже складно гілкується, так як можливо велику кількість нюансів. У перший раз код гілкується, коли ми визначаємо, чи більше вихідна ширина картинки, ніж ширина комірки, в яку її необхідно вписати. Але зауважте, в коді ніде не перевіряється, чи не менше чи висота зображення, ніж висота рамки. Якби я це написав, код подвоївся б удвічі, тому я вдався до деякої хитрості.

Розглянемо наступні рядки коду:

Ця ділянка коду перевіряє, по якій стороні необхідно проводити стиснення.

$ width, $ height - розміри осередку.

$ realW, $ realH - розміри вихідного зображення.

$ rotate - прапор, що говорить, що ми як би повернули зображення.

У цій ділянці коду ми міняємо поняття місцями. Ширина стає довжиною і навпаки. Нагадаю - це необхідно для того, щоб розмір коди не подвоївся.

Також в кінці функції є ще один блок, який міняє місцями значення в повернутому масиві сторін:

Мабуть, варто пояснити пару змінних з коду:

$ limX - максимальна ширина нового зображення. Якщо вона перевищується, то зображення стискується по описаних вище правил.

$ limY - максимальна висота нового зображення.

$ possH - висота нового зображення після пропорційного масштабування по ширині.

Слід зауважити, що зображення не обрізається під розміри осередку. Насправді все невидимі на сторінці фотоальбому частини картинок залишаються в цілості й схоронності, просто на сторінці вони ставляться на фон своїх осередків (div`ов) і центруються. Виходить, що області, які нам завгодно не бачили, щоб зберегти рівну сітку фотографій, залишаються за кадром. Робиться це так:

І css-властивості:

Ось і все, все можливості нашого класу ми розглянули, проте до цих пір не знаємо, як зберегти зображення ...

збереження зображення

Для збереження зображення використовується функція save (). Вона зберігає зображення, ідентифікатор якого зберігається в члені класу - image.

Ось так можна зберегти отримане зображення:

Перший параметр вказує каталог, куди слід зберегти зображення. Другий - ім'я файлу. Третій - його тип (jpg, png, gif). Четвертий параметр відповідає за те, чи варто перезаписувати файл, якщо файл з таким ім'ям вже існує. Четвертий параметр - якість jpg-зображення.

А ось і сам код функції:

Якщо тип зображення переданий ні, фото збережеться в вихідному форматі. Якщо переданий тип не є одним з трьох основних типів, то повернеться false. У разі успіху повернеться адреса нового зображення.

Використання

Часто може знадобитися зробити кілька змін з вихідним зображенням. Це не забороняється і робиться наступним чином:

Я ж рекомендую робити коротше і елегантніше - через ланцюжок викликів. Тепер стане зрозуміло, чому при ресайз, кроп і створенні мініатюр ми завжди повертали поточний об'єкт класу. Ось як це буде виглядати:

Чи не правда, зовнішній вигляд і зручні?

Все, весь функціонал описаний. На даний момент не можу ручатися, що клас працездатний в абсолютно всіх випадках, але в більшості їх - це так. Я його продовжу допрацьовувати і додавати, можливо, новий функціонал. Від вас чекаю відгуків, критики і пропозицій. Користуйтеся на здоров'я! 🙂

исходник класу

Що ж тоді робити?
У чому ж проблема?
Що ж зробимо ми?
Але що, якщо фото сильно витягнуте?


Новости
  • Виртуальный хостинг

    Виртуальный хостинг. Возможности сервера распределяются в равной мере между всеми... 
    Читать полностью

  • Редизайн сайта

    Редизайн сайта – это полное либо частичное обновление дизайна существующего сайта.... 
    Читать полностью

  • Консалтинг, услуги контент-менеджера

    Сопровождение любых интернет ресурсов;- Знание HTML и CSS- Поиск и обновление контента;-... 
    Читать полностью

  • Трафик из соцсетей

    Сравнительно дешевый способ по сравнению с поисковым и контекстным видами раскрутки... 
    Читать полностью

  • Поисковая оптимизация

    Поисковая оптимизация (англ. search engine optimization, SEO) — поднятие позиций сайта в результатах... 
    Читать полностью