Базы данныхИнтернетКомпьютерыОперационные системыПрограммированиеСетиСвязьРазное
Поиск по сайту:
Подпишись на рассылку:

Назад в раздел

Растровые изображения в Java.

div.main {margin-left: 20pt; margin-right: 20pt} Растровые изображения в Java.

Вначале о модели растровых изображений в java. В java используется следующая модель представления растрового изображения: производитель - потребитель - наблюдатель и класс утилит Image. Производитель реализует интерфейс ImageProducer, потребитель - ImageConsumer, а наблюдатель - ImageObserver из пакета java.awt.image. Иллюстрацией работы этой модели может стать процесс загрузки изображения из сети. Вначале продюсер читает размеры картинки и методом void setDimension(int width, int height) передаёт потребителю размеры картинки, потом, в случае gif файла, читает таблицу цветов изображения, производитель создаёт новую таблицу цветов, роль которой выполняет IndexColorModel и методом setColorModel пересылает её потребителю. В случае jpeg файла производитель пересылает DirectColorModel потребителю тем же методом. После этого производитель информирует потребителя методом setHints, в каком порядке он будет выдавать информацию, собственно кодирующую изображение. Этот порядок может быть следующим: выдавать картинку горизонтальными линиями, в произвольном порядке, одним "куском", покадрово (в случае наличия анимации), одиночными точками или постепенно в порядке сверху-вниз, справа-налево. После установки порядка выдачи, производитель начинает методом setPixels заполнять буфер потребителя. Соответственно, в зависимости от выбора передачи изображения, это происходит мгновенно (как в случае MemoryImageSource - одного из классов, реализующего интерфейс ImageProducer) или постепенно, по мере получения информации из потока и раскодирования её, как это получается при загрузке картинки из jpeg или gif файла из сети или с диска. По завершении передачи данных, производитель вызывает метод ImageComplete. Если конец передачи данных произошел из-за ошибки, этот метод вызывается с флагом ImageConsumer.IMAGEERROR, если из-за отмены пересылки, то с флагом ImageConsumer.IMAGEABORT. При пофреймовой загрузки анимированного файла, по окончанию загрузки каждого фрейма тоже вызывается метод ImageComplete, но с флагом ImageConsumer.SINGLEFRAMEDONE. По полному завершению процесса без ошибок, выбрасывается флаг ImageConsumer.STATICIMAGEDONE.

Для полного счастья программиста в java имеется вышеупомянутый третий интерфейс - ImageObserver. Он применяется для третьей заинтересованной стороны. Например, его реализует java.awt.Component и его наследники. Соответственно при вызове команды Image.getHeight(this) из наследников Component, в метод передаётся ссылка на класс, реализующего интерфейс наблюдателя. Поэтому, если нужна частая работа с картинками через класс Image или Graphics, а класс не является наследником Component, то в определении класса достаточно указать implements ImageObserver, в заголовке класса импортировать java.awt.image.* и написать метод boolean imageUpdate(Image img, int infoflags, x, y, width, height). Этот метод будет вызываться каждый раз, когда будут производится действия над картинкой, если в методах вызывающих это действие есть упоминание этого класса.

Подробнее в этом интерфейсе поможет разобраться документация для java, а так как у меня не стоит задача повторять её, то описывать флаги переменной infoflags я не буду, скажу лишь вкратце, что метод imageUpdate вполне может заменить класс MediaTracker, поскольку MediaTracker тоже реализует интерфейс ImageObserver и использует imageUpdate для задач по загрузке изображений. Также полезно знать, что класс PixelGrabber реализует интерфейс ImageConsumer, и если хочется написать его замену, то можно воспользоваться RGBImageFilter, реализующим тот же интерфейс, чтобы получить BITMAP "снимок" картинки.

Кстати, о фильтрах - все фильтры реализуют интерфейс ImageConsumer, но при этом важно знать, что фильтр имеет потоковое вычисление и нужно дождаться команды ImageComplete или воспользоваться MediaTracker, чтобы получить полностью обработанную картинку, а не обработанный её кусок с флагом ImageConsumer.IMAGEABORT.

Полезным знанием о фильтрах (как они устанавливаются через ImageFilteredSourse, я писать не буду - это детально описано в документации к java) также является установка и снятие в RGBImageFilter флажка обработки ColorModel. Дело в том, что при применении IndexColorModel невозможно использование всей ARGB палитры и для обработки каждого пикселя именно в ARGB режиме в этом классе нужно установить boolean canFilterIndexColorModel как false.

Полезными фильтрами являются CropImageFilter - он вырезает определённую область в картинке, ReplicateScaleFilter и AreaAverangingScaleFilter - эти фильтры осуществляют сжатие/растягивание картинки, причём второй делает "гладкое" растягивание. Все фильтры определены в пакете java.awt.image и доступны через класс Image - каждый раз, когда нужно вырезать кусок из картинки, растянуть/сжать со сглаживанием или без, Image вызывает именно эти фильтры, поэтому для скорости иногда можно вызвать их самостоятельно.

Теперь о кодировании компонент Alpha Red Green Blue в Int значении пикселя. Int значения этих компонентов можно получить с помощью операции сдвига/отсечения:

Если с - это цвет в int представлении, то
a = (c & 0xff000000)>>24;
r = (c & 0xff0000)>>16;
g = (c & 0xff00)>>8;
b = (c & 0xff);
, где a, r, g и b соответственно значения компонентов от 0 до 255.

Обратную трансформацию можно получить командой с = ((a << 24) | ((r << 16) | ((g << 8) | b))); Интересно, что массив, получаемый с помощью PixelGrabber, без установки ColorModel, содержит пиксели, записанные именно в таком формате, чем и можно воспользоваться. Также не стоит забывать, что значение 0 для alpha означает непрозрачность, а 255 - абсолютную прозрачность.

Теперь о ColorModel. Этот класс является совершенно бесполезным в случае преобразования картинки, но совершенно незаменимым, если нужно установить только цвета CMYK или использовать другую специальную не RGB палитру. Набор ColorModel достаточно подробно описан в документации, поэтому я опущу его описание.

В заключении о том, что я здесь не упомянул: я не рассказал о способах вывода картинки в Graphics и о рисовании Graphics в картинку. Не упомянул о новых классах, вошедших в пакет Image в java2 - это RenderableImage и несколько интерфейсов работы с ними, поскольку весьма удачный интерфейс работы с ними есть у Graphics2, а ускорять работу смысла нету - это достаточно быстрые классы, более чем на половину реализованные через машинные коды JVM. Так же не стал касаться проблем сериализации изображений и записи их в файл в известных форматах - последняя проблема решается пакетом JIMI, который можно найти через сайт java.sun.com, введя JIMI в строку поиска.

И пара советов по использованию класса Image.

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

Примерный код процесса загрузки/кэширования для аплета я привожу здесь:

MediaTracker mt = new MediaTracker(this);
img_in = getImage("http://somehost/someimage");
mt.addImage(img_in, 0);
try{mt.waitForID(0);}
catch(Exception e){}
mt.removeImage(img_in);
int w = img_in.getWidth(this), h = img_in.getHeight(this), img_g[] = new int[w*h+1];
PixelGrabber pg = new PixelGrabber(img_in, 0, 0, w, h, img_g, 0, w);
try{pg.grabPixels();}
catch(Exception e){}
img_in = createImage(new MemoryImageSource(w, h, img_g, 0, w));

Обратите внимание на частоту this - эта переменная везде, кроме конструктора MediaTracker, указывает на аплет, как на класс с интерфейсом ImageObserver. Аплет наследует этот интерфейс у Component.

И второй совет - если вам потребовалось использовать гладкое расширение/сжатие, причём сжатие идёт после расширения картинки, то используйте метод Image.getScaledInstance c флагом hints = Image.SCALE_AREA_AVERAGING - это улучшит качество результата.

Ну вот, пожалуй, и всё...



  • Главная
  • Новости
  • Новинки
  • Скрипты
  • Форум
  • Ссылки
  • О сайте




  • Emanual.ru – это сайт, посвящённый всем значимым событиям в IT-индустрии: новейшие разработки, уникальные методы и горячие новости! Тонны информации, полезной как для обычных пользователей, так и для самых продвинутых программистов! Интересные обсуждения на актуальные темы и огромная аудитория, которая может быть интересна широкому кругу рекламодателей. У нас вы узнаете всё о компьютерах, базах данных, операционных системах, сетях, инфраструктурах, связях и программированию на популярных языках!
     Copyright © 2001-2021
    Реклама на сайте