Масштабируем изображения в веб приложениях с примерами для ASP.Net MVC – часть 1

Прежде чем начать я бы хотел сказать несколько слов. Изначально я хотел написать статью о том, как создать ActionResult для контроллеров ASP.Net MVC, который позволяет масштабировать изображения. Но после того, как я начал писать эту статью я понял, что будет полезней если я немного расширю ее, добавив теоретическую часть и обзор способов масштабирования картинок как на сервере, так и на клиенте. Поэтому эта статья будет состоять из двух частей: первая часть содержит необходимую теорию и обзор методов, которые могут использоваться как в ASP.Net MVC, так и с другими технологиями веб разработки (напр. ASP.Net или Sharepoint), а во второй части я опишу, как решать проблемы, поставленные в первой части статьи, средствами ASP.Net MVC: см. часть 2. На этом закончим небольшое вступление и перейдем непосредственно к делу.

Большинство веб разработчиков в их практике работают с изображениями. При этом многие также сталкиваются с проблемой их корректного масштабирования на веб сайтах. В чем собственно проблема? Предположим что у нас есть e-commerce приложение и мы хотим отображать товары на веб сайте приложения. Как обычно имеется список категорий в левой части, так что пользователи могут выбрать товары какой категории они хотят просмотреть. Например, зайдем на http://www.amazon.com и выберем какую-нибудь категорию. При этом мы увидим что то подобное (я выбрал более менее нейтральную категорию с детскими игрушками 🙂 ):

image_thumb1

Я специально добавил стрелки, обозначающие границы размера изображений. Как видите большинство изображений имеют приблизительно одну и ту же ширину и высоту. В свою очередь это делает общий вид страницы более эстетичным и дружественным для пользователя. Но в жизни изображения товаров могут иметь совершенно разные пропорции, и было бы очень неэффективно для бизнеса, если персонал компании, ответственный за наполнение контента, вручную выравнивали бы пропорции изображений (хотя я знаю некоторые интернет-магазины, в которых практикуется такая практика). Как можно автоматизировать этот процесс?

Рассмотрим несколько подходов:

  • Статические изображения – картинки масштабируются во время загрузки на сервер и хранятся на отдельном сервере изображений или в базе данных;
  • Обработка на клиенте – размеры картинок выравниваются на клиентской стороне с использованием javascript (напр. jQuery scale plugin) или css;
  • Обработка на сервере – картинки масштабируются динамически на сервере.

Как я уже сказал в предисловии к этой статье я сделаю обзор этих методов. Но сначала давайте формализуем задачу. У нас есть различные изображения товаров (с разными коэффициентами пропорции) и мы хотим отображать иконки товаров в одинаковых div-ах (т.е. родительские div-ы картинок имеют одинаковый размер, который меньше чем реальный размер изображений) с сохранением пропорций изображений:

image_thumb5

Алгоритм следующий: необходимо определить минимум из двух коэффициентов и затем масштабировать изображения, используя следующие формулы:

image_thumb3

Как я уже говорил, предполагаем, что размер изображения больше чем размер div-ов (k < 1), т.е. рассматриваем уменьшение первоначальных размеров. Этот алгоритм сохраняет коэффициент пропорций (т.к. ширина и высота умножаются в итоге на один и тот же коэффициент) и позволяет подогнать размер картинок к размеру родительского div-а (т.к. мы использовали минимум из двух коэффициентов, это гарантирует что изображение целиком вместится в div).

Вернемся теперь к методам, которые могут быть использованы для реализации этого алгоритма. Посмотрим сначала, как это реализовано на Amazon. Изучив свойства картинок с помощью, к примеру, firebug, можно видеть что это статические изображения, расположенные на одном из серверов Amazon-а (напр. http://ecx.images-amazon.com/images/I/41zku-TbXmL._SL120_.jpg). Также ширина и высота изображений указаны в атрибутах тега <img>:

<img height="95" width="120" src="..."/>

Это один из подходов – каждый раз когда новый товар добавляется в каталог, автоматически генерируется его уменьшенное изображение и загружается на сервер изображений (имея ввиду их обороты, я не думаю что персонал Amazon-а делает это вручную 🙂 ).

Описанный подход достаточно неплохой. Он имеет хорошие показатели производительности, т.к. большинство браузеров кэшируют статические изображения очень хорошо. Также нам не надо беспокоится о масштабировании, т.к. картинки выравнены под нужный размер в момент создания товара. Но вместе с тем этот подход недостаточно гибок и адаптируем к изменению layout-а. Что будет если дизайн магазина поменяется и нам потребуется изменить размеры изображений товаров? Одно из решений – мы можем использовать css стили для настройки размеров изображений, определив css селектор для изображений с сохранением оригинальных пропорций. Напр., для пропорции 10:8 мы можем написать:

.icon
{
    width: 100px;
    height: 80px;
}

(Я не буду детально рассматривать этот способ, так что напр. масштабирование изображений с использованием единиц измерения em вне скопа этой статьи). Этот подход работает вполне неплохо, когда вы хотите уменьшить размер, т.к. большинство браузеров делают это с приемлемым качеством:

image_thumb19

Для тестирования я использовал IE 8, Opera 10.6, FF 3.0.19, Chrome 5.0.375.70. Как видите большинство браузеров уменьшили изображение вполне неплохо. Но что будет если мы увеличим размеры изображений с использованием css:

image_thumb15

image_thumb17

Здесь мы немного увеличили размеры с использованием css и качество ухудшилось во всех браузерах (и оно будет тем хуже, чем больше отличия между начальным размером и конечным). На всех картинках во всех браузерах наблюдается размытие. По моему мнению, не очень рационально сознательно идти на ухудшение качества, если у нас есть картинки с изначальным большим размером, которые можно уменьшить (потому что как мы видели уменьшение работает лучше). Какие альтернативы у нас есть? Одна из них – мы можем изменить все картинки к новому статическом размеру снова, что тем не менее, не поможет нам решить эту же проблему в будущем. Так что это не очень эффективный метод если у нас миллионы картинок и при этом изменяется layout. Другой подход, который мы можем использовать – масштабировать картинки динамически.

Мы рассмотрели подход со статическими изображениями и назвали его плюсы и минусы. Теперь рассмотрим другой подход с использованием javasctipt и css (масштабирование на клиенте). При этом картинки не выравниваются в момент загрузки на сервер – они имеют оригинальный размер. Плюс этого метода в том, что не требуется дополнительной работы – персонал компании, ответственный за наполнение контента на веб сайт, просто загружают изображения из любого источника (это может быть DVD каталог или веб сайт производителя) к примеру в базу данных магазина или на файловую систему. Наша задача – показать все картинки, которые имеют разные размеры и коэффициенты пропорции с более менее однообразным размером, используя javasctipt и css.

Когда вы используете javascript (напр. плагин jQuery, указанный выше), то при первой загрузке страницы пользователи могут увидеть скачок размеров картинок, т.к. сначала браузер загружает изображения с оригинальными размерами и затем javascript изменяет их. На следующих загрузках браузеры покажут картинки из кэша, но, как мне кажется, вы не захотите чтобы ваши пользователи видели как “скачет” размер картинок каждый раз, когда вы добавили новый товар в каталог. Также подход с использованием javascript не очень надежный. Я не имею ввиду ситуацию когда клиентский браузер не поддерживает javascript (по последним исследованиям таких меньше 1% и в этом случае пользователи будут иметь проблемы не только с вашим приложением 🙂 ). Если javascript код упадет по каким-либо причинам, пользователи увидят очень некрасивую страницу со сломанным layout-ом, т.к. все изображения товаров будут иметь оригинальные размеры.

Другой способ реализации алгоритма, описанного выше – использовать css. Вы можете укзать статический width в селекторе и height: auto (или наоборот):

.icon
{
    width: 100px;
    height: auto;
}

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

image_thumb4

Это, определенно, не совсем то, что нам нужно, т.к. мы хотели вместить изображения в родительский div целиком с сохранением оригинальных пропорций. В css есть полезные свойства, которые мы можем применить для решения данной задачи: max-width и max-height. Давайте посмотрим, что будет если мы применим следующий css класс к нашим изображениям:

.icon
{
    max-width: 100px;
    max-height: 80px;
}

Вот результат:

image_thumb31

Этот подход работает неплохо во всех браузерах, которые я использовал для тестирования (IE, Opera, FF, Chrome). Хорошо, мы можем использовать его на нашем сайте. Но что если нам нужно масштабировать изображения там, где css не поддерживается? Напр. нам нужно уметь генерировать pdf или сводное изображениям по товарам нашего каталога. Для этого случая нам нужны картинки с предопределенным статическим размером, чтобы добавить их в наш графический каталог. Чтобы сделать это, нам нужно рассмотреть еще один метод: масштабирование изображений на сервере. Это мы сделаем во второй части статьи: см. https://sadomovalex.wordpress.com/2010/09/25/scale-images-in-aspnet-mvc-part2.

Реклама

Об авторе sadomovalex

Старший инженер, team lead, консультант. Работаю в стеке .Net. Последние несколько лет занимаюсь разработкой enterprise приложений под Sharepoint, чему и будет в основном посвящена тематика этого блога. Также активно использую и интересуюсь ASP.Net MVC, DDD, TDD, Agile. Активно участвую в жизни многих профессиональных сообществ, SPb .Net UG, SPb ALT.Net, rsdn, Finland SP UG и др.
Запись опубликована в рубрике ASP.Net MVC, UI. Добавьте в закладки постоянную ссылку.

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

Заполните поля или щелкните по значку, чтобы оставить свой комментарий:

Логотип WordPress.com

Для комментария используется ваша учётная запись WordPress.com. Выход / Изменить )

Фотография Twitter

Для комментария используется ваша учётная запись Twitter. Выход / Изменить )

Фотография Facebook

Для комментария используется ваша учётная запись Facebook. Выход / Изменить )

Google+ photo

Для комментария используется ваша учётная запись Google+. Выход / Изменить )

Connecting to %s