Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Секреты программирования для Internet на Java

.pdf
Скачиваний:
181
Добавлен:
02.05.2014
Размер:
3.59 Mб
Скачать

получения всех изображений и только потом начинать мультипликацию.

Класс MediaTracker, входящий в иерархию java.awt, дает превосходный способ выполнения и управления этим процессом. Основная идея MediaTracker состоит в том, что когда изображение создано, оно добавляется к списку объектов, отслеживаемых MediaTracker. Каждому посреднику назначается некоторое значение приоритета, и программист может в любое время приостановить операции, пока все объекты с заданным приоритетом не будут готовы для отображения. Класс MediaTracker в настоящее время поддерживает только изображения, но фирма Sun в обозримом будущем планирует расширить его до проигрывания звуковых фрагментов и, возможно, видеоклипов. Наиболее полезные методы, предлагаемые классом MediaTracker, перечислены в табл. 9-5.

Таблица 9-5. Наиболее полезные методы класса MediaTracker

Метод

Описание

MediaTracker(Component) Создает новый MediaTracker, который будет посредником для данного компонента.

addImage(Image, int)

Добавляет изображение к посреднику с определенным уровнем

 

приоритета.

addImage(Image, int, int, Добавляет изображение к посреднику с уровнем приоритета,

int)

определяемым первым целым числом. Ширина и высота изображения

 

задаются следующими значениями.

boolean checkAll()

Проверяет, чтобы все прослеживаемые посредники завершили

 

загрузку. Если данные уже не загружаются, этот метод не начинает их

 

загрузку.

boolean checkAIl(boolean) Проверяет, чтобы все прослеживаемые посредники завершили загрузку. Если объекты еще не загружаются и булевский параметр равен true, этот метод начинает их загрузку.

waitForAII()

Ждет, пока все прослеживаемые посредники не будут завершены.

waitForAIl(long)

Ждет, пока все отслеживаемые посредники не будут завершены или

 

пока пройдет определенное число миллисекунд.

WaitForlD(int)

Ждет, пока все посредники с определенным уровнем приоритета не

 

будут завершены.

waitForlD(int, long)

Ждет, пока все посредники с определенным уровнем приоритета не

 

будут завершены или пока пройдет определенное число миллисекунд.

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

InterruptedException при использовании метода MediaTracker waitForAll - мы приостанавливаем выполнение текущего потока и непосредственно или косвенно должны проверять исключения:

MediaTracker tracker;

tracker = new MedlaTracker(this); Image i;

i = getImage(imageURL); tracker.addImage( i, 1); try {

tracker.waitForAll();

} catch (InterruptedException e) {}

Создание изображений

Мы можем теперь загружать изображения из сети и гарантировать их своевременную доставку. А что если мы хотим создавать наши собственные изображения? Раз класс Image определен с модификатором abstract, мы не можем создавать изображения непосредственно. Класс Component предоставляет методы createImage, которые могут использоваться для создания новых пустых объектов класса Image. Для вывода графики в эти пустые изображения мы можем использовать метод getGraphics для запроса объекта Graphics.

СОВЕТ Класс Canvas представляет собой удобный подкласс класса Component. В отличие от большинства других используемых подклассов Component, Canvas не расширяет контейнер. Canvas не может содержать другие компоненты, но, так как класс Image не пропадает из класса

Ⱦɚɧɧɚɹ ɜɟɪɫɢɹ ɤɧɢɝɢ ɜɵɩɭɳɟɧɚ ɷɥɟɤɬɪɨɧɧɵɦ ɢɡɞɚɬɟɥɶɫɬɜɨɦ %RRNV VKRS Ɋɚɫɩɪɨɫɬɪɚɧɟɧɢɟ ɩɪɨɞɚɠɚ ɩɟɪɟɡɚɩɢɫɶ ɞɚɧɧɨɣ ɤɧɢɝɢ ɢɥɢ ɟɟ ɱɚɫɬɟɣ ɁȺɉɊȿɓȿɇɕ Ɉ ɜɫɟɯ ɧɚɪɭɲɟɧɢɹɯ ɩɪɨɫɶɛɚ ɫɨɨɛɳɚɬɶ ɩɨ ɚɞɪɟɫɭ piracy@books-shop.com

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

Класс Component также дает нам некоторые методы для проверки состояния наших изображений и для подготовки их к выводу, хотя, вероятно, проще использовать MediaTracker, чтобы хранить указатели на них. Все эти методы перечислены в табл. 9-6.

Таблица 9-6. Создание изображений с помощью класса Component

Метод

Описание

createlmage(int, int)

Создает новое пустое изображение определенной ширины и

 

высоты.

createlmage(ImageProducer)

Запрашивает изображение из данного ImageProducer. Этот

 

интерфейс описан ниже в разделе "Интерфейсы для

 

асинхронных изображений" этой главы.

boolean prepareImage(lmage,

Готовит изображение к выводу на экран. Параметр

ImageObserver)

ImageObserver указывает объект, которому посылается

 

состояние изображения; это непосредственно объект

 

Component. Этот метод возвращает булевское значение, готово

 

или нет изображение для вывода.

boolean preparelmage(Image, int, Готовит к выводу на экран изображение с шириной и высотой, int, ImageObserver) определенными целочисленными параметрами. Параметр

ImageObserver работает таким же образом, как в предыдущем методе.

Самый простой способ создания изображений для вашего собственного проекта состоит в том, чтобы создать новый пустой объект Image и использовать метод getGraphics класса Image для непосредственного рисования изображения с помощью методов paint класса Graphics (перечисленных в табл. 9-1 и 9-2). Как мы уже говорили выше, это все еще не дает нам возможности иметь дело с изображением на уровне пикселов. Чтобы работать на уровне пикселов, нам нужно хотя бы поверхностное знакомство с несколькими интерфейсами, разработанными для работы с асинхронными изображениями.

Интерфейсы для асинхронных изображений

Класс java.awt.Image предоставляет три интерфейса - ImageProducer, ImageConsumer и ImageObserver, - которые обеспечивают программистов непротиворечивой средой для создания и обработки данных Image при анимации в реальном масштабе времени. Один из методов createImage, обеспечиваемых классом Component, основан на ImageProducer и передает ему начальные графические данные для Image. Методы ImageProducer для рисования и подготовки изображений требуют, чтобы ImageConsumer послал им данные о пикселах изображения. ImageObserver наблюдает за процессом и получает модификации от ImageProducer, когда новые данные становятся доступными.

Некоторые реализации этих интерфейсов обеспечиваются в Java API. Мы кратко опишем интерфейсы и затем перейдем к их конкретным реализациям в следующем разделе. Среднему программисту никогда не понадобится реализовывать эти интерфейсы, но важно понять то, что фактически происходит, чтобы эффективно использовать изображения.

Интерфейс ImageProducer

Интерфейс ImageProducer должен быть реализован классами, которые могут производить данные для Image. ImageProducer может использоваться как параметр для метода createImage класса Component. Этот интерфейс ответственен за предоставление данных для объекта Image. Интерфейс ImageProducer состоит из пяти методов, перечисленных в табл. 9-7.

Таблица 9-7. Методы интерфейса ImageProducer

Mетод

Описание

addConsumer (ImageConsumer)

Добавляет заданный lmageConsumer к списку

 

потребителей, заинтересованных в получении данных

 

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

boolean isConsumer (lmageConsumer) Возвращает булевское значение, показывающее,

www.books-shop.com

 

зарегистрирован ли данный lmageConsumer для получения

 

данных изображения с этим lmageObserver.

removeConsumer (ImageConsumer)

Удаляет заданный ImageConsumer из списка потребителей,

 

заинтересованных в получении данных изображения.

requestTopDownLeftRightResend

Запрашивает, чтобы изображение снова было послано в

(ImageConsumer)

порядке следования пикселов слева направо и сверху вниз.

startProduction (lmageConsumer)

Регистрирует, что данный ImageConsumer заинтересован в

 

получении данных, и начинает выводить изображение.

Интерфейс ImageConsumer

Интерфейс ImageProducer разработан для использования совместно с интерфейсом ImageConsumer. Интерфейс ImageConsumer должен быть реализован классами, которые заинтересованы в получении пикселов изображения из ImageProducer.

Нам не нужно задумываться о создании ImageConsumer - его функциональные возможности уже встроены в Java API. Методы, необходимые для использования интерфейса ImageConsumer, перечислены в табл. 9-8. Большинство этих методов предназначено для вызова ImageProducer, когда данные изображения становятся доступными.

 

Таблица 9-8. Методы интерфейса ImageConsumer

Метод

Описание

imageComplete (int)

ImageProducer вызывает этот метод, когда изображение готово или если

 

произошла ошибка при загрузке изображения. Целочисленный параметр

 

указывает состояние изображения. Возможные состояния изображения

 

перечислены в табл. 9-10.

SetColorModel

Устанавливает класс ColorModel, используемый изображением. Класс

(ColorModel)

ColorModel описан в разделе "Манипулирование изображениями".

SetDimensions (int,

Устанавливает ширину и высоту изображения.

int)

 

setHints (int)

Устанавливает любые сообщения, доступные из lmageObserver. Они могут

 

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

 

Целочисленный параметр содержит побитовое ИЛИ всех требуемых

 

сообщений. Возможные сообщения перечислены в табл. 9-9.

SetProperties

Устанавливает свойства, связанные с изображением. Иногда комментарии

(Hashtable)

или описание включаются наряду с данными изображения. Используется

 

метод ключей для определения, находится ли что-нибудь в хеш-таблице.

SetPixels (int, int, int, Устанавливает пикселы в прямоугольнике, заданном первыми четырьмя int, ColorModel, целыми числами. ColorModel указывает ColorModel, используемую

byte[], int, int) изображением. Массив типа byte содержит фактические данные пиксела, а последние два целых числа содержат начальное значение индекса и число пикселов в каждой строке (размер просмотра). Пиксел с расположением (X, Y) внутри прямоугольника находится в массиве по адресу, заданному следующей формулой: Y * длина_строки + X (+ начальный индекс, если отличен от нуля).

SetPixels (int, int, int, Делает то же, что и предыдущий метод, но использует целочисленный int, ColorMode, int[], массив вместо массива типа byte.

int, int)

Изображение во время создания может находиться в каком-то из определенных состояний. Кроме того, ImageProducer может выдавать зарегистрированным ImageConsumer сообщения (hints) о генерируемых им пикселах. Методы setHints и imageComplete передают эти состояния и сообщения интерфейсу ImageConsumer в виде целых чисел. В ImageConsumer возможные значения сообщений и состояний определены как статические целые. Они перечислены в табл. 9-9 и 9-10. Если ImageProducer требуется передать больше одного из этих сообщений и состояний изображения, он возвратит побитовое ИЛИ соответствующих состояний (более подробно см. врезку "Манипулирование битами").

 

Таблица 9-9. Сообщения из ImageProducer

Сообщение

Значение

RANDOMPIXELORDER Пикселы будут переданы без определенного порядка.

www.books-shop.com

TOPDOWNLEFIRIGHT Пикселы будут переданы в порядке сверху вниз и справа налево.

COMPLETESCANLINES Пикселы будут переданы в полных растровых строках (горизонтальные строки).

SINGLEPASS

Пикселы будут переданы за один проход, и каждый пиксел будет

 

установлен только однажды. Для некоторых изображений, особенно в

 

формате JPEG, пикселы передаются за несколько проходов, в которых

 

каждый следующий уточняет предыдущий.

SINGLEFRAME

Изображение содержит только один фрейм графических данных, и он уже

 

полный, ImageProducer не будет изменять изображение позже.

 

Таблица 9-10. Сообщения о состоянии из lmageProducer

Состояние

Значение

IMAGEERROR

При записи данных изображения произошла ошибка.

SINGLEFRAMEDONE Один фрейм графических данных полон, но последующие фреймы еще не готовы.

STATICIMAGEDONE Изображение готово, и ImageProducer не будет больше передавать данные для этого изображения.

IMAGEABORTED Изображение преднамеренно прервано.

Интерфейс ImageObserver

Для тех классов, которые не заинтересованы в получении обязательно всех пикселов, связанных с изображением, но которым требуется информация о продвижении самого процесса создания, фирма Sun обеспечила интерфейс ImageObserver. Этот интерфейс состоит из одного метода imageUpdate и большого количества переменных состояния, определенных в интерфейсе как статические целые. Эти переменные состояния очень похожи по полезности и реализации на переменные состояния и сообщения класса ImageConsumer. Метод интерфейса ImageObserver и его переменные перечислены в табл. 9-11.

Манипулирование битами

Вспомним, что целые числа сохраняются в памяти виртуальной машины Java как последовательность из 32 битов (см. главу 4, "Синтаксис и семантика"). Поразрядное ИЛИ двух целых чисел дает новое целое число, которое имеет значение 1 в каждой позиции, где бит по крайней мере одного из целых чисел имеет значение 1. Например, в памяти виртуальной машины Java целое число 6 представляется как ...0110. Целое число 12 выглядит как ...1100. Поразрядное ИЛИ этих двух целых чисел равно 14: ...1110.

Поразрядное ИЛИ любой комбинации состояний или сообщений гарантирует нам уникальное целочисленное значение. Это происходит потому, что каждое из статических целых чисел, связанных со специфическим состоянием или сообщением, является уникальной степенью двойки, представляемой в памяти как последовательность 32 битов, в которой имеется только один бит со значением 1 (например, 0100).

Поразрядное И двух целых чисел дает целое число, которое имеет значение 1 только в тех позициях, где биты в каждом из целых чисел равны 1. Например, 0110 & 1100 = 0100.

Чтобы выяснить, содержит ли состояние или сообщение интересующую нас информацию, переданную ImageProducer в ImageConsurner, можно использовать поразрядный оператор И.

Немного позже в этой главе мы применим операторы сдвига. Левый оператор поразрядного сдвига обозначается как <<. Он сдвигает левый операнд влево на число битов, определяемых правым операндом. Например, 6 << 1 = 12.

Правый оператор с разрядным сдвигом, >>, работает так же, но сдвигает операнд вправо.

 

Таблица 9-11. Метод и переменные интерфейса ImageObserver

Метод и

Описание

переменныe

boolean

ImageProducer вызывает этот метод, когда информация, предварительно

imageUpdate

запрошенная ImageObserver, становится доступной. Параметр Image

(Image, int, int, int, возвращает ссылку на изображение в запросе, а первый целочисленный

int, int)

параметр содержит поразрядное ИЛИ всех используемых состояний.

 

Последние четыре целых числа обычно интерпретируются как

 

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

www.books-shop.com

WIDTH

Указывает, что ширина изображения известна и может быть выведена из

 

прямоугольника ограничения.

HEIGHT

Указывает, что высота изображения известна и может быть выведена из

 

прямоугольника ограничения.

PROPERTIES

Свойства изображения известны и могут быть получены через метод

 

getProperty класса Image.

SOMEBITS

Большое количество пикселов (но не все) являются теперь доступными.

 

Гарантируется, что прямоугольник ограничения заполнен.

FRAMEBITS

Полный фрейм многофрейменного изображения теперь доступен.

 

Прямоугольник ограничения игнорируется.

ALLBITS

Изображение является полным, и прямоугольник ограничения игнорируется.

ERROR

Произошла ошибка во время создания изображения.

ABORT

Создание изображения было прервано прежде, чем изображение было

 

закончено. Если при этом не появилось сообщение ERROR, последующее

 

обращение к любым данным изображения завершает его создание.

Подобно другим интерфейсам, описанным здесь, ImageObserver никогда не придется реализовывать большинству программистов. Класс java.awt.Component реализует интерфейс ImageObserver, позволяя ему и всем его потомкам использовать и отображать асинхронные изображения. Всякий раз, когда достаточное количество новых пикселов станет доступным для вывода копии изображения с желаемой или пониженной разрешающей способностью, класс Component запрашивает перерисовку изображения.

Эти интерфейсы могут казаться несколько тяжелыми и неуклюжими для работы, но их преимущества реализованы некоторыми классами, предлагаемыми Java API (в частности, ImageConsumer). Эти классы позволяют декодировать изображения в массив целых чисел и обратно - создавать изображения из целочисленного массива, а также создавать фильтры для изменения изображений.

Манипулирование изображениями

В дополнение к интерфейсам для обработки асинхронных изображений, пакет java.awt.image дает несколько их удобных специфических реализаций. Эти реализации позволяют выполнять с изображениями операции низкого уровня: захват пикселов из изображений с помощью класса PixelGrabber, создание изображений из массивов пикселов с помощью класса MemoryImageSource, фильтрация существующих изображений с помощью класса ImageFilter. Все классы, описанные в этом разделе, являются частью пакета java.awt.image Java API.

Захват пикселов

Класс PixelGrabber - это реализация интерфейса ImageConsumer для захвата пикселов и данных о цвете из изображения или ImageProducer. Можно захватывать все пикселы в данном изображении или только в какой-то прямоугольной части изображения. Конструкторы и другие уникальные методы класса PixelGrabber приведены в табл. 9-12.

Таблица 9-12. Конструкторы и методы класса PixelGrabber

Конструктор /

Описание

Метод

 

PixelGrabber (Image, int, int, int, int, int[], int, int)

Создает новый PixelGrabber, который возвращает пикселы из данного изображения. Первые четыре целочисленных параметра указывают прямоугольник области ограничения, из которой мы хотим получать пикселы. Значения пикселов будут скопированы в целочисленный параметр массива; размер этого массива должен быть равен, по крайней мере, произведению количества элементов по ширине на количество элементов по высоте. Последние два целых числа указывают начальный индекс пиксела в массиве и число пикселов в каждой строке, которые будут помещены в массив (то есть ширину выбранной области).

PixelGrabber

Создает новый PixelGrabber, который возвращает пикселы изображения,

(lmageProducer, int,

указанного ImageProducer. Остальная часть параметров идентична

int, int, int, int[], int,

параметрам предыдущего конструктора.

int)

 

grabPixels()

Запрашивает у Image или ImageProducer передачу пикселов. Этот метод

www.books-shop.com

 

блокируется, пока данные не получены. Если он был вызван прежде, чем

 

данные прибыли, произойдет исключение InterruptedException.

grabPixels (long)

Запрашивает у Image или ImageProducer передачу пикселов. Этот метод

 

блокируется, пока данные не получены или пока не пройдет число

 

миллисекунд, определенное параметром. Если этот метод был вызван

 

прежде, чем данные прибыли или истекло заданное время, произойдет

 

исключение InterruptedException.

int status()

Возвращает состояние изображения, которое представляет собой

 

поразрядное ИЛИ всех переменных состояния lmageObserver.

Следующий фрагмент кода иллюстрирует использование класса PixelGrabber:

PixelGrabber grabber;

int width = myImage.getWidth(this); int height = myImage.getHeight(this); int ary[] = new ary[width*height];

grabber = new PixelGrabber(mylmage,0,0,width,height, ary,0 ,width); try {

grabber. grabPixels();

} catch (InterruptedException e) {} int status = grabber.status();

If ((status & ImageObserver.ABORT) || (status & ImageObserver.ERROR)) {

//произошла ошибка при выборе пикселов изображения

}else {

for (int i=0; Kary-length; i++) {

// делайте что-нибудь с пикселами в массиве

}

}

В этом коде мы используем PixelGrabber, чтобы запросить все пикселы изображения. После того как запрос выполнен, мы проверяем состояние пикселов; если передача была прервана или произошла какая-то ошибка, мы обрабатываем соответствующую ситуацию. В противном случае мы можем считывать пикселы из массива, который мы передали PixelGrabber.

Цветовые модели

Получив массив пикселов, мы должны с ним что-то сделать. Каждый пиксел представляется в этом массиве одиночным целым числом. Необходимо извлечь из этого целого числа все данные, которые нам нужны, чтобы нарисовать или как-то иначе интерпретировать пиксел. Расположение каждого пиксела в изображении может быть выведено из позиции в массиве, и мы используем класс ColorModel, чтобы интерпретировать целое число непосредственно как цвет.

Почти любой цвет может быть представлен как уникальная комбинация оттенков красного, синего и зеленого. Существуют и другие комбинации, основанные на других наборах цветов, но они используются исключительно в компьютерной графике. Почти все цветные мониторы получают каждый пиксел из комбинации красных, синих и зеленых точек. Класс ColorModel не только позволяет нам разбирать целые числа в массиве пикселов и разбивать каждый из них на красную, синюю и зеленую составляющие, но и определять степень прозрачности. Компонент прозрачности управляет выводом пиксела: если пиксел прозрачен, цвет фона преобразуется в отображаемый цвет пиксела. На рис. 9-2 показано наложение частично прозрачного изображения на непрозрачное.

www.books-shop.com

Рис. 9.2.

Класс ColorModel определен с модификатором abstract, хотя два его расширения обеспечиваются в Java API и описаны ниже в этом разделе. В табл. 9-13 приведен список методов класса ColorModel. Обратите внимание, что метод getRGBdefault объявлен с модификатором static и, таким образом, может использоваться для возвращения ссылки времени выполнения на неабстрактный по умолчанию RGB ColorModel.

Таблица 9-13. Методы класса ColorModel

Метод Описание

ColorModel (int) Создает цветовую модель, которая поддерживает цвета из определенного числа битов. Число битов непосредственно управляет числом уникальных цветов, возможных в этой модели. Значение восемь битов на пиксел дает 256 различных цветов.

int getAlpha (int) Возвращает компонент прозрачности пиксела, определенного целочисленным параметром.

int getBlue (int) Возвращает синюю составляющую пиксела, определенного целочисленным параметром.

int getGreen (int) Возвращает зеленую составляющую пиксела, определенного целочисленным параметром.

int getRed (int) Возвращает красную составляющую пиксела, определенного целочисленным параметром.

int getPixelSize() Возвращает число битов на пиксел.

int getRGB (int) Возвращает значение пиксела, определенного параметром, в заданной по умолчанию цветовой модели RGB.

static ColorModel Возвращает заданный по умолчанию ColorModel RGB, используемый пакетом getRGBdefault () java.awt.image. Эта схема распределяет восемь битов для каждого первичного

компонента цветности и прозрачности, который дает 256 градаций красного, синего и зеленого цветов и прозрачности, что дает общее количество 16777216 цветов (не считая оттенков прозрачности).

Есть два базовых пути кодирования красного, синего и зеленого цвета и степени прозрачности, каждый из которых представляет собой целое число из некоторого количества бит

в32-битном целом. При первом способе целочисленное значение пиксела обрабатывается как индекс массива, а красный, синий и зеленый цвета и степень прозрачности берутся из внутренних таблиц палитры. Упорядочивать цвета в таблицах не нужно; соответствие устанавливается создателем модели. IndexColorModel расширяет основной класс ColorModel так, что вы можете создавать новый класс ColorModel, использующий вашу собственную палитру. При построении модели вы создаете массивы компонентов цвета. Когда программист запрашивает цвет из модели, он использует значение пиксела как позицию в массиве и возвращает значение этой позиции из соответствующего массива.

Второй способ извлечения четырех компонентов цвета из 32-разрядного целого числа состоит

втом, чтобы выделить части целого числа в разрядные массивы, размеры которых должны в

www.books-shop.com

сумме давать 32. Эта идея проиллюстрирована на рис. 9-3. Каждый разрядный массив содержит информацию о красной, синей и зеленой составляющих и о прозрачности полного цвета. Например, можно выделить 26 битов для красного, 2 бита для синего, 3 бита для зеленого и 1 бит для прозрачности. Согласно этой схеме, мы будем иметь 67108864 возможных оттенков красного, 4 оттенка синего, 8 оттенков зеленого и 2 оттенка прозрачности (полностью непрозрачный или прозрачный). Класс DirectColorModel представляет собой расширение класса ColorModel, который отображает значения пиксела на компоненты цвета, используя эту методику.

Рис. 9.3.

Теперь массив целочисленных значений пикселов, возвращенных классом PixelGrabber, имеет смысл. ColorModel, используемый классом PixelGrabber, - это заданная по умолчанию модель цвета RGB, и мы можем использовать для нее методы, перечисленные в табл. 9-13, чтобы извлечь из пикселов информацию о цвете. Мы можем добавить следующий код к циклу, приведенному в нашем более раннем примере, чтобы проанализировать конкретные компоненты цвета из массива пикселов:

ColorModel cm = ColorModel.getRGBdefault(); int pixel;

for (int l=0; i<ary. length, i++) { Pixel = ary[i]; cm.getRed(pixel); cm.getBlue(pixel); cm.getGreen(pixel); cm.getAlpha(pixel );

}

Мы показали, как преобразовать изображения в массивы и как отобразить значения из этих массивов в компоненты цвета с помощью класса ColorModel. Обратное преобразование, превращение массивов в изображения, также легко выполнить с помощью класса

MemoryImageSource.

Преобразование массивов в изображения

Класс MemoryImageSource дает способ преобразовывать массивы целых чисел в пикселы для класса Image. Класс MemoryImageSource реализует интерфейс ImageProducer и может использоваться как параметр для метода createImage класса Component. Конструкторы для класса MemoryImageSource приведены в табл. 9-14. Создав новый класс MemoryImageSource, мы можем использовать его для вывода новых изображений с помощью методов createImage класса

Component.

Таблица 9-14. Конструкторы класса MemorylmageSource

Конструктор Описание

MemoryImageSource (int, Создает новый ImageProducer, который строит изображение из ColorModel, byte[], int, int) значений пикселов в байтовом массиве, передаваемом как

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

MemorylmageSource (int, int, Работает так же, как предыдущий конструктор. Параметр

ColorModel, byte[], int, int, Hashtable устанавливает свойства изображения. Hashtable)

MemorylmageSource (int, int, Создает новый ImageProducer из данного целочисленного ColorModel, int[], int, int) массива.

www.books-shop.com

MemorylmageSource(int, int,

Создает новый ImageProducer из данного целочисленного

ColorModel, int[], int, int,

массива.

Hashtable)

 

MemorylmageSource (int, int,

Создает новый ImageProducer из данного целочисленного

int[], int, int)

массива, используя заданную по умолчанию цветовую модель

 

RGB.

MemorylmageSource (int, int,

Создает новый ImageProducer из данного целочисленного

ColorModel, int[], int, int,

массива, используя заданную по умолчанию цветовую модель

Hashtable)

RGB.

Этот класс лучше всего проиллюстрировать примером. Ниже мы дадим полный апплет, который генерирует из целочисленного массива и выводит изображение. Мы создадим красные составляющие из каждого пиксела, добавляя соответственно отмасштабированные синусы координат X и Y каждого пиксела, аналогично мы создадим синие составляющие каждого пиксела, но уже добавляя косинусы координат X и Y. Окончательные значения каждого пиксела получаются объединением красных и синих составляющих цвета со 100-процентным значением прозрачности в поразрядной операции ИЛИ, сдвигая компоненты, пока они не будут выровнены с соответствующими позициями в заданной по умолчанию схеме цвета RGB. Снимок экрана с готовым изображением показан на рис. 9-4.

Рис. 9.4.

Пример 9-2. Использование класса MemoryImageSource. import java.awt.*;

import java.awt.image.*; import java.applet.*;

public class ShadeApplet extends Applet { Image myImage;

public void init() { resize(250,250);

int ary[] = new int[250*250]; for (int i=0; i<250; i++) {

for (int j=0; j<250; j++) {

double x = (16*Math.PI*j/250); double y = (16*Math.PI*i/250);

double p = (Math.sin(x)+Math.sin(y)+2)/4; int redvalue = (int)Math.round(p*255); double q = (Math.cos(x)+Math.cos(y)+2)/4; int bluevalue = (int)Math.round(q*255); ary[i*250+j] =

(255<<24)|((redvalue)<<16)|(bluevalue);

}

}

MemoryImageSource mis;

mis = new MemoryImageSource(250,250,ary,0,250); myImage = createImage(mis);

}

public void paint(Graphics g) { g.drawImage(myImage,0,0,this);

}

}

www.books-shop.com

Фильтрация изображений

Теперь мы можем создавать изображения непосредственно на уровне битов, без использования графических примитивов, предлагаемых классом Graphics. Мы можем даже управлять изображениями, загруженными из сети; с помощью PixelGrabber мы можем получать значения пикселов из массива. Мы можем провести и обратный процесс, используя класс MemoryImageSource. Java API предоставляет два класса, разработанные специально для этой задачи, - FilteredImageSource и ImageFilter.

Класс FilteredImageSource реализует интерфейс ImageProducer. Он берет ImageProducer и ImageFilter в качестве параметров конструкции. Создавая изображение, он получает данные о пикселах из ImageProducer, определенного в конструкции. Потом изменяет эти данные непротиворечивым способом, продиктованным ImageFilter, и посылает измененные данные обратно через ImageConsumer. Класс ImageFilter реализует интерфейс ImageConsumer. Он не изменяет данные о пикселах. Java API дает два простых расширения, которые позволяют вставлять цветной фильтр или вырезать некоторую область для нового изображения.

Класс RGBImageFilter по умолчанию не выполняет никакой фильтрации цвета, но трансформирует значение пиксела и ColorModel, используемые изображением для заданной по умолчанию модели цвета RGB. Чтобы заставить его фильтровать цвета, мы должны расширить метод filterRGB этого класса для выполнения необходимой нам фильтрации. Рассмотрим пример, который удаляет из изображения весь красный цвет.

Пример 9-3. Фильтр удаления красного цвета. import java.awt.image.*;

public class NoRedFilter extends RGBImageFilter { public int filterRGB(int x, int y, int rgb) {

int alpha = (rgb & 0xff000000)>>24; int red = (rgb & 0x00ff0000)>>16; int green = (rgb & 0x0000ff00)>>8; int blue = (rgb & 0x000000ff);

return ((alpha<<24)|(green<<8)|(blue));

}

}

Сначала мы расчленяем целую переменную rgb, указывая цвет пиксела в заданной по умолчанию схеме цвета RGB, и затем добавляем прозрачность, зеленую и синюю составляющие обратно в значение RGB, полностью игнорируя красное значение. Обратите внимание, что, так как мы передаем координаты X и Y, мы могли бы изменять цвет фильтрации, основываясь на расположении, но для нашего простого фильтра это ни к чему. Класс RGBColorFilter - удобный фильтр, который вы можете развивать для своих собственных нужд, потому что в случае необходимости он выполняет преобразование к заданной по умолчанию модели цвета RGB.

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

FilteredlmageSource fis; CroplmlageFllter filter;

filter =new CroplmageFilter(0,0,10,10);

fis = new FilteredlmageSource(mylmage.getSource(),filter); Image myNewlmage = createlmage(fis);

Что дальше?

Классы, описанные в этой главе, позволяют легко и просто генерировать и изменять графические изображения. Класс Graphics позволяет вам выводить изображение с помощью простых графических примитивов, подобных тем, что используются в программах рисования. Расширенные средства создания изображений Java API также позволяют преобразовывать изображения в целочисленные массивы и наоборот, давая точный контроль над изображениями. Фильтрация изображений дает среднему Java-программисту возможность конкурировать с такими программами, как Adobe Photoshop, хотя медлительность используемых при этом вычислений ограничивает полезность этих фильтров до тех пор, пока не станут доступными компиляторы в машинный код.

www.books-shop.com