Глава 18 - Работа с изображениямиJava работает с наиболее популярными во Всемирной паутине форматами изображений - JPEG и GIF. JPEG лучше подходит для естественных цветных изображений, таких, как фотографии, а формат GIF является наилучшими для графических эмблем, изображений кнопок, и т.п. Сначала мы загрузим изображение с помощью очень короткой программы. Затем мы научимся использовать классы, которые управляют загрузкой одного или нескольких изображений. Кроме того, существует набор абстрактных классов, которые помогают создать поток изображений, и фильтры, позволяющие обращаться к отдельным элементам изображений и модифицировать их. Простой загрузчик изображений Простейший случай - загрузка в страницу одиночного изображения. Вот маленький апплет, выполняющий эту работу: /* <title>SimpleImageLoad</title> * <applet code="SimpleImageLoad" width=300 height=150> * <param name="img" value="mupk.gif"> * </applet> */ import java.applet.*; import java.awt.*; public class SimpleImageLoad extends Applet { Image art; public void init() { art = getImage(getDocumentBase(), getParameter("img")); } public void paint(Graphics g) { g.drawImage(art, 0, 0, this); } } Метод paint использует drawlmage с четырьмя аргументами: это ссылка на изображение art, координаты левого верхнего угла рисунка х, у и объект типа ImageObserver. Мы поговорим подробнее об ImageObserver в следующем параграфе; здесь мы использовали this в качестве имени ImageObserver, поскольку он встроен в апплет. Когда этот апплет запускается, он в методе init начинает загрузку art. Процесс загрузки изображения по сети хорошо заметен - SimpleImageLoad.html, поскольку встроенный интерфейс ImageObserver вызывает процедуру paint при каждом поступлении новой порции данных из сети. Вы можете использовать ImageObserver для отслеживания загрузки изображения, а в это время выводить на экран другую информацию. ImageObserver ImageObserver - это абстрактный интерфейс, используемый для получения сообщения о создании изображения, Метод imageUpdate из ImageObserver - это все, что вы должны реализовать в своем апплете для его использования. В то время, как вы получаете информацию о загрузке, вы можете показывать любую понравившуюся вам мультипликацию, индикатор степени завершения загрузки или любую другую заставку. Для использования ImageObserver в своем подклассе Applet вы должны добавить в него строку implement ImageObserver, как показано в этом фрагменте программы: public class MyApplet extends Applet implement ImageObserver { Затем вам придется вставить в свой класс метод imageUpdate для интерфейса ImageObserver, как показано в следующем фрагменте : public boolean imageUpdate(Image img, int status, int x, int у int width, int height) { if((status & ALLBITS) != 1) { System.out.println("Still processing the image"); return true; } else { System.out.println("Done processing the image"); return false; } } Метод imageUpdate вызывается с изображением Image, которое находится в процессе изменения, целым параметром status, отражающим состояние изменения, и с координатами прямоугольника (x, у, width, height), которые соответствуют различным величинам в зависимости от информационных флагов, перечисленных ниже. ImageUpdate должен возвращать false по окончании загрузки изображения и true - если изображение еще обрабатывается. Целая переменная status поразрядно проверяется на наличие одного или нескольких флагов. Возможные флаги и информация, которую они несут, перечислены ниже:
Теперь давайте рассмотрим программный пример, который использует ImageObserver для показа количества обработанных строк изображения и выводит эту информацию (переменная progress) на консоль: /* <title>ObservedImageLoad</title> * <applet code="ObservedImageLoad" width=290 height=140> * <param name="img" value="mupk.gif"> * </applet> */ import java.applet.*; import java.awt.*; import java.awt.image.*; public class ObservedImageLoad extends Applet implements Runnable, ImageObserver { Image art; Dimension d; int progress; Thread motor; boolean loaded; public void init() { art = getImage(getDocumentBase(), getParameter("img")); loaded = false; progress = 0; } public void paint(Graphics g) { d = this.getSize(); loaded = g.drawImage(art, 0, 0, this); } public boolean imageUpdate(Image img, int info, int x, int y, int width, int height) { if((info & ALLBITS) != 1) { if(progress<d.height) { progress = progress+height; } System.out.println(progress+"/"+d.height); return true; } else { return false; }} public void start() { motor = new Thread(this); motor. start(); } public void stop() { motor.stop(); } public void run() { motor.setPriority(Thread.MIN_PRIORITY); while(!loaded) { // update progress indicator (5 fps) repaint(); try { motor.sleep(200); } catch(InterruptedException e) {} } } } Метод imageUpdate обрабатывает статус загрузки изображения. Информация о статусе передается через переменную info, с которой сравнивается статическая переменная ALLBITS. Если еще не получено все изображение, то мы добавляем величину heihgt к общему числу обработанных строк изображения. Для проверки этой концепции мы выводим количество обработанных строк изображения на консоль. Метод run перерисовывает апплет пять раз в секунду (каждые 200 миллисекунд) до тех пор, пока изображение art не загрузится. То, как долго монитор статуса загрузки будет работать, зависит от скорости передачи данных изображения по сети - ObservedImageLoad.html. MediaTracker MediaTracker - это класс, предоставляющий удобный интерфейс для контроля статуса нескольких изображений. В следующих версиях этот класс будет контролировать другие мультимедийные форматы, такие, как звуковые файлы. Для использования MediaTracker нужно создать новый объект этого класса и использовать метод addImage для контроля статуса загрузки. Используйте MediaTracker при загрузке группы изображений. Пока все изображения, которые вас интересуют, не загружены, пользователя будет развлекать демонстрационный экран. ImageProducer ImageProducer - это абстрактный интерфейс для объектов, которые готовят данные для Image. Объект, который реализует интерфейс ImageProducer, должен предоставлять массивы целых или байтовых переменных, представляющих собой данные изображений. Давайте познакомимся с очень полезным классом MemoryImageSource, реализующий ImageProducer. Мы создадим новый объект Image из данных, которые сгенерировал ImageProducer. MemorylmageSource MemoryImageSource - класс, используемый для создания нового изображения из массива пикселей. Вот конструктор, используемый для создания объекта MemoryImageSource: MemoryImageSource(int width, int height, int pixel[], int offset, int scanLineWidth) Объект MemoryImageSource собирается из массива целых величин pixel[] в используемой по умолчанию модели цветов RGB для генерации данных объекта Image. В используемой по умолчанию цветовой модели пиксель - это целая величина состоящая из Alpha, Red, Green и Blue (OxAARRGGBB). Величина Alpha обозначает степень прозрачности элемента изображения. MemoryImageSource возвращает объект ImageProducer, который используется с createImage для получения изображения, пригодного к использованию. Приведенный ниже короткий пример создает MemoryImageSource, используя вариант простого алгоритма (побитовое исключающее ИЛИ значений х и у координат каждого элемента изображения) из книги Gerard J.Holzmann "Beyond Photography, The Digital Darkroom". /* <title>Memory Image Generator</title> * <applet code="MemoryImager" width=256 height=256> * </applet> */ import java.applet.*; import java.awt.*; import java.awt.image.*; public class MemoryImager extends Applet { Image art; Dimension d; public void init() { generateImage(); } public void generateImage() { int pixels[] = new int[d.width * d.height]; int i = 0; int r, g, b; for(int y=0; y<h; y++) { for(int x=0; x<h; x++) { r = (x^y)&0xff; // red is x XOR у g = (x*2^y*2)&0xff; //green is 2x XOR 2y b = (x*4^y*4)&0xff; // blue is 4x XOR 4y pixels[i++]=(255<<24)|(r<<16)|(g<<8)|b; } } art = createImage (new MemoryImageSource(d.width,d.height,pixels,0,d.width)); } public void paint(Graphics g) { g.drawlmage(art, 0, 0, this); } } Посмотрите как это интересное изображение выглядит на экране - MemoryImager.html. ImageFilter и ImageFilterSource Подклассы классов ImageFilter и ImageFilterSource используются совместно для создания новых изображений фильтрованием уже существующих. С двумя такими подклассами из пакета java.awt.image вы сейчас познакомитесь. CropImageFilter CropImageFilter создает новое изображение из фрагмента существующего. Использование этого фильтра полезно тогда, когда вы хотите использовать несколько маленьких изображений в одном апплете. Загрузка по сети двадцати изображений по 2 Кбайта происходит намного медленнее, чем загрузка одного файла размером 40 Кбайт. Если ваши изображения - одинакового размера, вы можете собрать их в единый блок и использовать CropImageFilter для разделения блока на отдельные изображения в Java-клиенте. RGBImageFilter RGBImageFilter используется для получения данных о каждом пикселе изображения, которые мы можем модифицировать, и таким образом модифицировать изображение. Мультимедиа-горизонты Существующая система обработки изображений в Java пока не полностью поддерживает потребительские стандарты из-за ограниченной переносимости в сегодняшнем многообразии компьютерных платформ. Но в Java нет никаких "врожденных" ограничений на разработку мультимедийных приложений. Я уверен, что мы станем свидетелями больших успехов в развитии и совершенствовании этой технологии в течении ближайших лет. Поделитесь этой записью или добавьте в закладки | Полезные публикации |