Некоторые файлы, например анимационные GIF-файлы, могут содержать несколько изображений. Однако метод read() класса ImageIO позволяет считывать только одно из них. Для чтения нескольких изображений нужно преобразовать источник входных данных(например, входной поток файла) в объект ImageInputStream:
1 2 |
InputStream in = ...; ImageInputStream imageIn = ImageIO.createImageInputStream(in); |
Затем следует соединить этот объект с программой чтения:
1 |
reader.setInput(imageIn, true); |
Второй параметр имеет значение true, а это означает, что входной поток позволяет читать данные только в прямом направлении. Значение false допускает произвольный доступ, обеспечиваемый либо за счет буферизации, либо путем организации произвольного доступа к файлу. Произвольный доступ позволяет эффективно выполнять определенные операции. Например, для подсчета количества изображений в GIF-файле нужно прочитать полностью весь файл. Если затем необходимо выбрать какой-то рисунок, то в режиме произвольного доступа не придется снова считывать весь входной поток.
Сказанное важно только для случаи чтения входного потока, содержащего несколько изображений, и при отсутствии в заголовке файла требуемой информации о формате рисунка(например, его номера). Для чтения файла можно применить показанный ниже простой фрагмент кода:
1 2 3 |
File f = ...; ImageInputStream imageIn = ImageIO.createImageInputStream(f); Reader.setInput(imageIn); |
Таким образом, при наличии объекта чтения можно считывать отдельные рисунки по известному индексу, отсчет которого начинается с нуля:
1 |
BufferedImage image = reader.read(index); |
Если для потока на входе установлен режим чтения ‘только вперед», то следует продолжать считывать рисунки до тех пор, пока метод read() не сгенерирует исключение IndexOutOgBoundsException. Для этого можно также вызвать метод getNumImages(), параметр которого имеет значение true, то есть разрешается поиск и подсчет количества изображений:
1 |
int n = reader.getNumImages(true); |
Если для входного потока задан режим просмотра «только вперед», данный метод генерирует исключение IllegalStateException. Кроме того, в качестве параметра метода getNumImages() может быть задано значение false. Если метод getNumImgaes() не может определить количество рисунков без проведения поиска, то он возвращает значение -1. В этом случае нужно считывать изображения до появления исключения IndexOutOfBoundsException.
Некоторые файлы могут содержать миниатюры, представляющие собой уменьшение версии основного изображения, предназначенные для предварительного просмотра. С помощью следующего вызова можно узнать количество миниатюр для изображения:
1 |
int count = reader.getNumThumbnails(index); |
Для получения миниатюры можно применить метод getThumbnail() с указанием индекса основного изображения и индекса самой миниатюры:
1 |
BufferedImage thumbnail = reader.getThumbnail(index, thumbnailIndex); |
Иногда необходимо получить размер рисунка еще до получения самого рисунка. Это особенно важно, когда речь идет о передаче рисунка очень большого размера или использовании очень низкоскоростного сетевого соединения. Для получения размеров рисунка с заданным индексом применяются следующие методы:
1 2 |
int width = reader.getWidth(index); int height = reader.getHeight(index); |
Для записи файла с несколькими рисунками нужно сначала создать объект ImageWriter, а затем с помощью класса IOImage перечислить все объекты, способные записывать изображения данного формата:
1 2 3 4 |
String format = . . .; ImageWriter writer = null; Iterator<ImageWriter> iter = ImageIO.getImageWritersByFormatName( format ); if(iter.hasNext()) writer = iter.next(); |
Затем следует преобразовать выходной поток в объект ImageOutputStream и подключить его к объекту записи:
1 2 3 |
File f = ...; ImageOutputStream imageOut = ImageIO,createImageOutputStream(f); writer.setOutput(imageOut); |
Каждое изображение нужно оформить в виде объекта IIOImage, затем(по желанию) составить список миниатюр и метаданные(например, алгоритм сжатия и информацию о цвете). В рассматриваемом здесь примере для списка миниатюр и метаданных заданы значения null. Более подробную информацию по данному вопросу вы найдете в документации по API.
1 |
IIOImage iioImage = new IIOImage(images[i], null, null); |
Для записи первого изображения используется метод write():
1 |
writer.write(new IIOImage(images[0], null, null)); |
Для всех последующих изображений выполняется проверка:
1 2 |
if(writer.canInsertImage(i)) writer.writeInsert(i, iioImage, null); |
Третий параметр может содержать объект ImageWriteParam, позволяющий указать такие подробности, как мозаичное расположение в сжатие. В этом примере в качестве третьего параметра используется значение null.
Не все форматы файлов могут содержать несколько изображений. В таком случае метод canInsertImage() возвращает для i > 0 значение false и сохраняется только один рисунок.
Кстати, на днях познакомился с интересным программистом который фанат в 1C. Если вас интересует доработка 1С то советую заказать услугу именно от знакомого. Час работы зависит от объема работ и составляет от 1300 рублей за час работы, что гораздо ниже, чем у других компаний.