TwelveMonkeys ImageIO обеспечивает расширенную поддержку формата файлов изображений для платформы Java посредством плагинов для пакета javax.imageio.*
.
Основная цель этого проекта — обеспечить поддержку форматов файлов, не поддерживаемых JDK. Поддержка этих форматов важна для возможности читать данные, найденные «в природе», а также для поддержания доступа к данным в устаревших форматах. Поскольку существует множество устаревших данных, мы видим необходимость в открытых реализациях программ чтения для популярных форматов.
Плагин | Формат | Описание | Р | Вт | Метаданные | Примечания |
---|---|---|---|---|---|---|
Батик | SVG | Масштабируемая векторная графика | ✔ | - | - | Требуется Батик |
ВМФ | Метафайл MS Windows | ✔ | - | - | Требуется Батик | |
БМП | БМП | Независимое от устройства растровое изображение MS Windows и IBM OS/2 | ✔ | ✔ | Родной, Стандартный | |
CUR | Формат курсора MS Windows | ✔ | - | - | ||
ICO | Формат значков MS Windows | ✔ | ✔ | - | ||
ДДС | ДДС | Формат поверхности MS Direct Draw | ✔ | - | Стандартный | |
HDR | HDR | Формат RGBE с расширенным динамическим диапазоном Radiance | ✔ | - | Стандартный | |
ИКНС | ИКНС | Изображение значка Apple | ✔ | ✔ | - | |
МКФ | МКФ | Формат файла обмена Commodore Amiga/Electronic Arts | ✔ | ✔ | Стандартный | |
JPEG | JPEG | Объединенная экспертная группа фотографов | ✔ | ✔ | Родной, Стандартный | |
JPEG без потерь | ✔ | - | Родной, Стандартный | |||
ПКХ | ПКХ | Формат ZSoft Paintbrush | ✔ | - | Стандартный | |
DCX | Многостраничный факсовый документ PCX | ✔ | - | Стандартный | ||
ПИКТ | ПИКТ | Формат изображения Apple QuickTime | ✔ | ✔ | Стандартный | |
ПНТГ | Формат изображения Apple MacPaint | ✔ | - | Стандартный | ||
ПНМ | ПАМ | NetPBM Portable Любая карта | ✔ | ✔ | Стандартный | |
ПБМ | Переносимая битовая карта NetPBM | ✔ | - | Стандартный | ||
ПГМ | Портативная серая карта NetPBM | ✔ | - | Стандартный | ||
ППМ | Портативная пиксельная карта NetPBM | ✔ | ✔ | Стандартный | ||
ПФМ | Портативная плавающая карта | ✔ | - | Стандартный | ||
PSD | PSD | Документ Adobe Photoshop | ✔ | (✔) | Родной, Стандартный | |
Промсвязьбанк | Большой документ Adobe Photoshop | ✔ | - | Родной, Стандартный | ||
СГИ | СГИ | Формат изображения кремниевой графики | ✔ | - | Стандартный | |
ТГА | ТГА | Формат изображения Truevision TGA | ✔ | ✔ | Стандартный | |
ThumbsDB | Thumbs.db | База данных Thumbs MS Windows | ✔ | - | - | Только формат на основе составного документа OLE2 |
ТИФФ | ТИФФ | Формат файла изображения с тегами Aldus/Adobe | ✔ | ✔ | Родной, Стандартный | |
БольшойTIFF | ✔ | ✔ | Родной, Стандартный | |||
ВебП | ВебП | Формат Google WebP | ✔ | - | Стандартный | |
XWD | XWD | Формат дампа окна X11 | ✔ | - | Стандартный |
Важное примечание по использованию Batik: прочтите «Проект Apache™ XML Graphics — Безопасность» и убедитесь, что вы используете обновленную и безопасную версию.
Обратите внимание, что форматы GIF, PNG и WBMP уже поддерживаются через API ImageIO с использованием стандартных плагинов JDK. Для форматов BMP, JPEG и TIFF плагины TwelveMonkeys обеспечивают расширенную поддержку форматов и дополнительные функции.
В большинстве случаев все, что вам нужно сделать, это просто включить плагины в свой проект и написать:
BufferedImage image = ImageIO . read ( file );
Это позволит полностью загрузить первое изображение файла в память.
Основная и самая простая форма записи:
if (! ImageIO . write ( image , format , file )) {
// Handle image not written case
}
Это запишет все изображение в один файл, используя настройки по умолчанию для данного формата.
Плагины обнаруживаются автоматически во время выполнения. Дополнительную информацию о том, как работает этот механизм, смотрите в FAQ.
Если вам нужен больший контроль над параметрами чтения и процессом чтения, общая идиома чтения выглядит примерно так:
// Create input stream (in try-with-resource block to avoid leaks)
try ( ImageInputStream input = ImageIO . createImageInputStream ( file )) {
// Get the reader
Iterator < ImageReader > readers = ImageIO . getImageReaders ( input );
if (! readers . hasNext ()) {
throw new IllegalArgumentException ( "No reader for: " + file );
}
ImageReader reader = readers . next ();
try {
reader . setInput ( input );
// Optionally, listen for read warnings, progress, etc.
reader . addIIOReadWarningListener (...);
reader . addIIOReadProgressListener (...);
ImageReadParam param = reader . getDefaultReadParam ();
// Optionally, control read settings like sub sampling, source region or destination etc.
param . setSourceSubsampling (...);
param . setSourceRegion (...);
param . setDestination (...);
// ...
// Finally read the image, using settings from param
BufferedImage image = reader . read ( 0 , param );
// Optionally, read thumbnails, meta data, etc...
int numThumbs = reader . getNumThumbnails ( 0 );
// ...
}
finally {
// Dispose reader in finally block to avoid memory leaks
reader . dispose ();
}
}
Запросите у читателя размеры исходного изображения, используя reader.getWidth(n)
и reader.getHeight(n)
не считывая сначала все изображение в память.
Также возможно читать несколько изображений из одного файла в цикле, используя reader.getNumImages()
.
Если вам нужен больший контроль над параметрами записи и процессом записи, общая идиома записи выглядит примерно так:
// Get the writer
Iterator < ImageWriter > writers = ImageIO . getImageWritersByFormatName ( format );
if (! writers . hasNext ()) {
throw new IllegalArgumentException ( "No writer for: " + format );
}
ImageWriter writer = writers . next ();
try {
// Create output stream (in try-with-resource block to avoid leaks)
try ( ImageOutputStream output = ImageIO . createImageOutputStream ( file )) {
writer . setOutput ( output );
// Optionally, listen to progress, warnings, etc.
ImageWriteParam param = writer . getDefaultWriteParam ();
// Optionally, control format specific settings of param (requires casting), or
// control generic write settings like sub sampling, source region, output type etc.
// Optionally, provide thumbnails and image/stream metadata
writer . write (..., new IIOImage (..., image , ...), param );
}
}
finally {
// Dispose writer in finally block to avoid memory leaks
writer . dispose ();
}
Для более продвинутого использования и информации о том, как использовать API ImageIO, я предлагаю вам прочитать Руководство по API ввода-вывода изображений Java от Oracle.
import com . twelvemonkeys . imageio . path . Paths ;
...
try ( ImageInputStream stream = ImageIO . createImageInputStream ( new File ( "image_with_path.jpg" )) {
BufferedImage image = Paths . readClipped ( stream );
// Do something with the clipped image...
}
Дополнительную информацию и пример кода см. в разделе «Поддержка Adobe Clipping Path» на Wiki.
Библиотека включает в себя операцию повторной выборки (изменения размера изображения), которая содержит множество различных алгоритмов, обеспечивающих превосходные результаты с разумной скоростью.
import com . twelvemonkeys . image . ResampleOp ;
...
BufferedImage input = ...; // Image to resample
int width , height = ...; // new width/height
BufferedImageOp resampler = new ResampleOp ( width , height , ResampleOp . FILTER_LANCZOS ); // A good default filter, see class documentation for more info
BufferedImage output = resampler . filter ( input , null );
Библиотека поставляется с операцией сглаживания, которую можно использовать для преобразования BufferedImage
в IndexColorModel
с использованием сглаживания диффузии ошибок Флойда-Стейнберга.
import com . twelvemonkeys . image . DiffusionDither ;
...
BufferedImage input = ...; // Image to dither
BufferedImageOp ditherer = new DiffusionDither ();
BufferedImage output = ditherer . filter ( input , null );
При использовании обычных шаблонов загрузки изображений попытка загрузить поврежденное изображение приведет к возникновению исключения IOException
.
BufferedImage image = null ;
try {
image = ImageIO . read ( file );
} catch ( IOException exception ) {
// Handle, log a warning/error etc
}
В этом сценарии, если изображение повреждено и ImageIO.read
выдает исключение, image
по-прежнему имеет null
— функция не может одновременно возвращать значение и выдавать исключение.
Однако в некоторых случаях можно получить полезные данные изображения из поврежденного изображения. Способ сделать это — использовать ImageReadParam
, чтобы установить BufferedImage
в качестве места назначения.
int width = reader . getWidth ( 0 );
int height = reader . getHeight ( 0 );
ImageTypeSpecifier imageType = reader . getRawImageType ( 0 );
BufferedImage image = imageType . createBufferedImage ( width , height );
ImageReadParam param = reader . getDefaultReadParam ();
param . setDestination ( image );
try {
reader . read ( 0 , param );
}
catch ( IOException e ) {
// Handle, log a warning/error etc
}
Теоретически это должно работать для всех плагинов, но результат во многом зависит от плагина/реализации. При использовании некоторых форматов и некоторых видов поврежденных файлов вы можете получить изображение, которое будет наиболее полезным. Однако вы должны быть готовы к тому, что это просто приведет к появлению пустого или пустого изображения.
Загрузите проект (используя Git):
$ git clone [email protected]:haraldk/TwelveMonkeys.git
Это должно создать папку с именем TwelveMonkeys
в вашем текущем каталоге. Перейдите в папку TwelveMonkeys
и введите команду ниже для сборки.
Создайте проект (используя Maven):
$ mvn package
В настоящее время рекомендуемым JDK для сборки является Oracle JDK 8.x.
Сборку можно выполнить с использованием OpenJDK, но некоторые тесты могут завершиться неудачно из-за незначительных различий между используемыми системами управления цветом. Вам нужно будет либо отключить рассматриваемые тесты, либо собрать систему вообще без тестов.
Поскольку для выполнения модульных тестов требуется довольно много памяти, вам, возможно, придется установить переменную среды MAVEN_OPTS
, чтобы предоставить процессу Java, запускающему Maven, больше памяти. Я предлагаю что-то вроде -Xmx512m -XX:MaxPermSize=256m
.
При желании вы можете установить проект в локальный репозиторий Maven, используя:
$ mvn install
Чтобы установить плагины, либо используйте Maven и добавьте необходимые зависимости в свой проект, либо вручную добавьте необходимые JAR-файлы вместе с необходимыми зависимостями в путь к классам.
Реестр ImageIO и механизм поиска служб обеспечат доступность плагинов для использования.
Чтобы убедиться, что плагин JPEG установлен и используется во время выполнения, вы можете использовать следующий код:
Iterator < ImageReader > readers = ImageIO . getImageReadersByFormatName ( "JPEG" );
while ( readers . hasNext ()) {
System . out . println ( "reader: " + readers . next ());
}
В первой строке должно быть напечатано:
reader: com.twelvemonkeys.imageio.plugins.jpeg.JPEGImageReader@somehash
Чтобы использовать плагин JPEG и TIFF с использованием Maven, добавьте в POM следующее:
...
< dependencies >
...
< dependency >
< groupId >com.twelvemonkeys.imageio</ groupId >
< artifactId >imageio-jpeg</ artifactId >
< version >3.12.0</ version >
</ dependency >
< dependency >
< groupId >com.twelvemonkeys.imageio</ groupId >
< artifactId >imageio-tiff</ artifactId >
< version >3.12.0</ version >
</ dependency >
<!--
Optional dependency. Needed only if you deploy ImageIO plugins as part of a web app.
Make sure you add the IIOProviderContextListener to your web.xml, see above.
-->
< dependency >
< groupId >com.twelvemonkeys.servlet</ groupId >
< artifactId >servlet</ artifactId >
< version >3.12.0</ version >
</ dependency >
<!--
Or Jakarta version, for Servlet API 5.0
-->
< dependency >
< groupId >com.twelvemonkeys.servlet</ groupId >
< artifactId >servlet</ artifactId >
< version >3.12.0</ version >
< classifier >jakarta</ classifier >
</ dependency >
</ dependencies >
Чтобы использовать плагин JPEG и TIFF в вашей IDE или программе, добавьте все следующие JAR-файлы в свой путь к классам:
twelvemonkeys-common-lang-3.12.0.jar
twelvemonkeys-common-io-3.12.0.jar
twelvemonkeys-common-image-3.12.0.jar
twelvemonkeys-imageio-core-3.12.0.jar
twelvemonkeys-imageio-metadata-3.12.0.jar
twelvemonkeys-imageio-jpeg-3.12.0.jar
twelvemonkeys-imageio-tiff-3.12.0.jar
Поскольку реестр плагинов ImageIO
( IIORegistry
) является «глобальным VM», он не работает должным образом с контекстами сервлетов «как есть». Это особенно заметно, если вы загружаете плагины из папки WEB-INF/lib
или classes
. Если вы не добавите ImageIO.scanForPlugins()
где-нибудь в своем коде, плагины могут вообще никогда не стать доступными.
Кроме того, контексты сервлетов динамически загружают и выгружают классы (используя новый загрузчик классов для каждого контекста). Если вы перезапустите приложение, старые классы по умолчанию останутся в памяти навсегда (потому что при следующем вызове scanForPlugins
это другой ClassLoader
, который сканирует/загружает классы, и, следовательно, они будут новыми экземплярами в реестре). Если попытка чтения будет предпринята с использованием одного из оставшихся «старых» читателей, могут возникнуть странные исключения (например, NullPointerException
при доступе к static final
инициализированным полям или NoClassDefFoundError
для неинициализированных внутренних классов).
Чтобы обойти как проблему обнаружения, так и утечку ресурсов, настоятельно рекомендуется использовать IIOProviderContextListener
, который реализует динамическую загрузку и выгрузку подключаемых модулей ImageIO для веб-приложений.
< web-app ...>
...
< listener >
< display-name >ImageIO service provider loader/unloader</ display-name >
< listener-class >com.twelvemonkeys.servlet.image.IIOProviderContextListener</ listener-class >
</ listener >
...
</ web-app >
Загрузка плагинов из WEB-INF/lib
без установленного прослушивателя контекста не поддерживается и не будет работать корректно.
Прослушиватель контекста не зависит от плагинов TwelveMonkeys ImageIO и может также использоваться с JAI ImageIO или другими плагинами ImageIO.
Другой безопасный вариант — поместить файлы JAR в общую или общую папку lib сервера приложений.
Для тех, кто переходит со старого пакета javax.servlet
на новый пакет jakarta.servlet
, доступна отдельная зависимость. Он содержит точно такие же классы сервлетов, как упоминалось выше, но построен на основе новых пакетов Jakarta EE. Зависимость имеет то же имя группы и идентификатор, что и раньше, но добавлен классификатор jakarta
, чтобы отличить ее от пакета, не относящегося к Джакарте.
См. пример зависимости Maven, чтобы узнать, как включить ее с помощью Maven. Gradle или другие инструменты сборки будут иметь аналогичные параметры.
Рекомендуемый способ использования плагинов — просто включить JAR-файлы в ваш проект как есть, через зависимость Maven или что-то подобное. Для использования библиотеки переупаковка не обязательна и не рекомендуется.
Однако, если вы хотите создать «толстый» JAR-файл или по какой-то причине хотите переупаковать JAR-файлы, важно помнить, что автоматическое обнаружение плагинов с помощью ImageIO зависит от механизма интерфейса поставщика услуг (SPI). Короче говоря, каждый JAR содержит специальную папку с именем META-INF/services
, содержащую один или несколько файлов, обычно javax.imageio.spi.ImageReaderSpi
и javax.imageio.spi.ImageWriterSpi
. Эти файлы существуют с одним и тем же именем в каждом JAR , поэтому, если вы просто распакуете все в одну папку или создадите JAR, файлы будут перезаписаны, а поведение не будет указано (скорее всего, в конечном итоге у вас будет установлен один плагин).
Решение состоит в том, чтобы убедиться, что все файлы с одинаковым именем объединены в один файл, содержащий всю информацию SPI каждого типа. Если вы используете плагин Maven Shade, вам следует использовать ServicesResourceTransformer для правильного объединения этих файлов. Вы также можете использовать ManifestResourceTransforme, чтобы получить правильное имя поставщика, информацию о версии и т. д. Другие «толстые» упаковщики JAR, вероятно, будут иметь аналогичные механизмы для объединения записей с одинаковым именем.
Последняя версия, которая будет работать на Java 7, — 3.9.4. Более поздние версии потребуют Java 8 или новее.
Общие зависимости
Зависимости ImageIO
Плагины ImageIO
Плагины ImageIO, требующие сторонних библиотек
Поддержка Photoshop Path для ImageIO
Поддержка сервлетов
Этот проект предоставляется в соответствии с одобренной OSI лицензией BSD:
Copyright (c) 2008-2022, Harald Kuhr
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
o Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
o Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
o Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
вопрос: Как мне его использовать?
Ответ: Самый простой способ — создать собственный проект с помощью Maven, Gradle или другого инструмента сборки с управлением зависимостями и просто добавить зависимости к конкретным нужным вам плагинам. Если вы не используете такой инструмент сборки, убедитесь, что у вас есть все необходимые JAR-файлы в пути к классам. См. раздел «Установка» выше.
вопрос: Какие изменения мне нужно внести в свой код, чтобы использовать плагины?
а: Короткий ответ: нет. Для базового использования, например ImageIO.read(...)
или ImageIO.getImageReaders(...)
, нет необходимости менять код. Большая часть функций доступна через стандартные API-интерфейсы ImageIO, и было уделено большое внимание тому, чтобы не вводить дополнительные API там, где они не нужны.
Если вы хотите использовать очень специфические/расширенные функции некоторых форматов, вам, возможно, придется использовать определенные API, например, настройку базового URL-адреса для изображения SVG, состоящего из нескольких файлов, или управление выходным сжатием файла TIFF.
вопрос: Как это работает?
а: Проект TwelveMonkeys ImageIO содержит плагины для ImageIO. ImageIO использует механизм поиска служб для обнаружения плагинов во время выполнения.
Все, что вам нужно сделать, это убедиться, что в вашем пути к классам есть JAR-файлы TwelveMonkeys ImageIO.
Дополнительную информацию о реестре и механизме поиска можно прочитать в документе IIORegistry API.
Мелкий шрифт: поставщики услуг TwelveMonkeys для JPEG, BMP и TIFF переопределяют метод onRegistration и используют механизм попарного частичного упорядочения IIOServiceRegistry
, чтобы убедиться, что он установлен до того, как Sun/Oracle предоставит JPEGImageReader
, BMPImageReader
TIFFImageReader
и Apple. предоставил TIFFImageReader
в OS X соответственно. Использование парного порядка не приведет к удалению каких-либо функций из этих реализаций, но в большинстве случаев вместо этого вы будете использовать плагины TwelveMonkeys.
вопрос: Почему нет поддержки распространенных форматов, таких как GIF или PNG?
Ответ: Короткий ответ: встроенная поддержка этих форматов в ImageIO считается достаточно хорошей как есть. Если вам нужна более высокая производительность записи PNG на Java 7 и 8, см. Backport JDK9 PNG Writer.
в: Когда следующий релиз? Каков текущий график выпуска?
О: Цель состоит в том, чтобы выпускать ежемесячные выпуски, содержащие исправления ошибок и небольшие новые функции. И ежеквартальные выпуски с более «основными» функциями.
в: Мне нравится этот проект! Как я могу помочь?
О: Посмотрите на открытые проблемы и посмотрите, есть ли какие-либо проблемы, которые вы можете помочь исправить, предоставить образец файла или создать тестовые примеры. Вы или ваша организация также можете стать спонсором через спонсоров GitHub. Предоставление финансирования позволит нам уделять больше времени исправлению ошибок и внедрению новых функций.
вопрос: А как насчет JAI? Некоторые форматы уже поддерживаются JAI.
о: Хотя JAI (и jai-imageio в частности) поддерживает некоторые из тех же форматов, у JAI есть некоторые серьезные проблемы. Самое очевидное:
вопрос: А как насчет JMagick или IM4Java? Неужели нельзя просто использовать то, что уже есть?
О: Хотя отличные библиотеки поддерживают широкий спектр форматов, библиотеки на основе ImageMagick имеют некоторые недостатки по сравнению с ImageIO.
Мы сделали это