TwelveMonkeys ImageIO는 javax.imageio.*
패키지용 플러그인을 통해 Java 플랫폼에 대한 확장된 이미지 파일 형식 지원을 제공합니다.
이 프로젝트의 주요 목표는 JDK에서 다루지 않는 파일 형식을 지원하는 것입니다. 이러한 형식에 대한 지원은 "야생"에서 발견된 데이터를 읽을 수 있을 뿐만 아니라 레거시 형식의 데이터에 대한 액세스를 유지하는 데 중요합니다. 기존 데이터가 많기 때문에 널리 사용되는 형식에 대한 판독기의 개방형 구현이 필요하다는 것을 알 수 있습니다.
플러그인 | 체재 | 설명 | 아르 자형 | 여 | 메타데이터 | 메모 |
---|---|---|---|---|---|---|
납결 염색법 | SVG | 확장 가능한 벡터 그래픽 | ✔ | - | - | 바틱이 필요합니다 |
WMF | MS Windows 메타파일 | ✔ | - | - | 바틱이 필요합니다 | |
BMP | BMP | MS Windows 및 IBM OS/2 장치 독립적인 비트맵 | ✔ | ✔ | 네이티브, 표준 | |
똥개 | MS Windows 커서 형식 | ✔ | - | - | ||
ICO | MS Windows 아이콘 형식 | ✔ | ✔ | - | ||
DDS | DDS | MS 직접 그리기 표면 형식 | ✔ | - | 기준 | |
HDR | HDR | Radiance High Dynamic Range RGBE 형식 | ✔ | - | 기준 | |
ICNS | ICNS | 애플 아이콘 이미지 | ✔ | ✔ | - | |
IFF | IFF | Commodore Amiga/Electronic Arts 교환 파일 형식 | ✔ | ✔ | 기준 | |
JPEG | JPEG | 공동사진가 전문가 그룹 | ✔ | ✔ | 네이티브, 표준 | |
JPEG 무손실 | ✔ | - | 네이티브, 표준 | |||
PCX | PCX | ZSoft 페인트 브러시 형식 | ✔ | - | 기준 | |
DCX | 다중 페이지 PCX 팩스 문서 | ✔ | - | 기준 | ||
PICT | PICT | Apple QuickTime 사진 형식 | ✔ | ✔ | 기준 | |
PNTG | Apple MacPaint 그림 형식 | ✔ | - | 기준 | ||
PNM | 팸 | NetPBM 휴대용 모든 지도 | ✔ | ✔ | 기준 | |
PBM | NetPBM 휴대용 비트 맵 | ✔ | - | 기준 | ||
PGM | NetPBM 휴대용 회색 지도 | ✔ | - | 기준 | ||
PPM | NetPBM 휴대용 Pix 지도 | ✔ | ✔ | 기준 | ||
PFM | 휴대용 플로트 지도 | ✔ | - | 기준 | ||
PSD | PSD | 어도비 포토샵 문서 | ✔ | (✔) | 네이티브, 표준 | |
PSB | Adobe Photoshop 대용량 문서 | ✔ | - | 네이티브, 표준 | ||
SGI | SGI | 실리콘 그래픽 이미지 형식 | ✔ | - | 기준 | |
TGA | TGA | Truevision TGA 이미지 형식 | ✔ | ✔ | 기준 | |
썸즈DB | Thumbs.db | MS 윈도우 썸즈 DB | ✔ | - | - | OLE2 복합 문서 기반 형식만 해당 |
사소한 말다툼 | 사소한 말다툼 | Aldus/Adobe 태그된 이미지 파일 형식 | ✔ | ✔ | 네이티브, 표준 | |
빅티프 | ✔ | ✔ | 네이티브, 표준 | |||
웹P | 웹P | Google WebP 형식 | ✔ | - | 기준 | |
XWD | XWD | X11 창 덤프 형식 | ✔ | - | 기준 |
Batik 사용에 대한 중요 참고 사항: Apache™ XML 그래픽 프로젝트 - 보안을 읽고 업데이트되고 안전한 버전을 사용하는지 확인하십시오.
GIF, PNG 및 WBMP 형식은 JDK 표준 플러그인을 사용하여 ImageIO API를 통해 이미 지원됩니다. 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 ();
}
고급 사용법과 ImageIO API 사용 방법에 대한 정보를 보려면 Oracle의 Java Image I/O API Guide를 읽어 보시기 바랍니다.
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...
}
자세한 내용과 예제 코드는 Wiki의 Adobe Clipping Path 지원을 참조하세요.
라이브러리에는 합리적인 속도로 탁월한 결과를 제공하는 다양한 알고리즘이 포함된 리샘플링(이미지 크기 조정) 작업이 함께 제공됩니다.
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 );
라이브러리에는 Floyd-Steinberg 오류 확산 디더를 사용하여 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을 실행하는 Java 프로세스에 더 많은 메모리를 제공하려면 환경 변수 MAVEN_OPTS
설정해야 할 수도 있습니다. -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
Maven을 사용하여 JPEG 및 TIFF 플러그인을 사용하려면 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 >
IDE 또는 프로그램에서 JPEG 및 TIFF 플러그인을 사용하려면 다음 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
이므로 레지스트리의 새 인스턴스가 되기 때문입니다). 나머지 "이전" 판독기 중 하나를 사용하여 읽기를 시도하면 이상한 예외(예: static final
초기화 필드에 액세스할 때 NullPointerException
, 초기화되지 않은 내부 클래스에 대해 NoClassDefFoundError
)가 발생할 수 있습니다.
검색 문제와 리소스 누출을 모두 해결하려면 웹 애플리케이션용 ImageIO 플러그인의 동적 로드 및 언로드를 구현하는 IIOProviderContextListener
를 사용하는 것이 좋습니다 .
< 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 또는 기타 빌드 도구에는 유사한 옵션이 있습니다.
플러그인을 사용하는 권장 방법은 Maven 종속성 또는 이와 유사한 것을 통해 JAR을 프로젝트에 있는 그대로 포함하는 것입니다. 라이브러리를 사용하기 위해 다시 포장할 필요는 없으며 권장되지 않습니다.
그러나 "fat" JAR을 생성하거나 어떤 이유로든 JAR을 다시 패키지하려는 경우 ImageIO의 플러그인 자동 검색이 SPI(서비스 공급자 인터페이스) 메커니즘에 따라 다르다는 점을 기억하는 것이 중요합니다. 즉, 각 JAR에는 하나 이상의 파일(일반적으로 javax.imageio.spi.ImageReaderSpi
및 javax.imageio.spi.ImageWriterSpi
)이 포함된 META-INF/services
라는 특수 폴더가 포함되어 있습니다. 이러한 파일은 모든 JAR에 동일한 이름으로 존재하므로 모든 것을 단일 폴더에 압축을 풀거나 JAR을 생성하면 파일이 덮어쓰여지고 동작이 지정되지 않습니다(단일 플러그인이 설치될 가능성이 높습니다).
해결 방법은 동일한 이름을 가진 모든 파일을 각 유형의 모든 SPI 정보를 포함하는 단일 파일로 병합하는 것입니다. Maven Shade 플러그인을 사용하는 경우 ServicesResourceTransformer를 사용하여 이러한 파일을 올바르게 병합해야 합니다. ManifestResourceTransforme를 사용하여 올바른 공급업체 이름, 버전 정보 등을 얻을 수도 있습니다. 다른 "fat" JAR 번들러에는 동일한 이름을 가진 항목을 병합하는 유사한 메커니즘이 있을 수 있습니다.
Java 7에서 실행되는 최신 버전은 3.9.4입니다. 이후 버전에는 Java 8 이상이 필요합니다.
일반적인 종속성
ImageIO 종속성
ImageIO 플러그인
타사 라이브러리가 필요한 ImageIO 플러그인
ImageIO에 대한 Photoshop 경로 지원
서블릿 지원
이 프로젝트는 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.
질문: 어떻게 사용하나요?
a: 가장 쉬운 방법은 Maven, Gradle 또는 종속성 관리 기능이 있는 기타 빌드 도구를 사용하여 자신만의 프로젝트를 빌드하고 필요한 특정 플러그인에 종속성을 추가하는 것입니다. 이러한 빌드 도구를 사용하지 않는 경우 클래스 경로에 필요한 모든 JAR이 있는지 확인하세요. 위의 설치 섹션을 참조하세요.
q: 플러그인을 사용하려면 코드를 어떻게 변경해야 합니까?
a: 간단히 대답하자면: 없음입니다. ImageIO.read(...)
또는 ImageIO.getImageReaders(...)
와 같은 기본 사용법의 경우 코드를 변경할 필요가 없습니다. 대부분의 기능은 표준 ImageIO API를 통해 사용할 수 있으며, 불필요한 API가 추가로 도입되지 않도록 세심한 주의를 기울였습니다.
일부 형식의 매우 구체적인/고급 기능을 사용하려면 여러 파일로 구성된 SVG 이미지에 대한 기본 URL을 설정하거나 TIFF 파일의 출력 압축을 제어하는 등 특정 API를 사용해야 할 수도 있습니다.
질문: 어떻게 작동하나요?
a: TwelveMonkeys ImageIO 프로젝트에는 ImageIO용 플러그인이 포함되어 있습니다. ImageIO는 서비스 조회 메커니즘을 사용하여 런타임에 플러그인을 검색합니다.
당신이 해야 할 일은 클래스 경로에 TwelveMonkeys ImageIO JAR이 있는지 확인하는 것입니다.
IIORegistry API 문서에서 레지스트리 및 조회 메커니즘에 대한 자세한 내용을 읽을 수 있습니다.
작은 글씨: JPEG, BMP 및 TIFF에 대한 TwelveMonkeys 서비스 제공자는 onRegistration 메소드를 대체하고 IIOServiceRegistry
의 쌍별 부분 주문 메커니즘을 활용하여 Sun/Oracle이 JPEGImageReader
, BMPImageReader
TIFFImageReader
및 Apple을 제공하기 전에 설치되도록 합니다. OS X에서 각각 TIFFImageReader
제공했습니다. 쌍별 순서를 사용하면 이러한 구현에서 기능이 제거되지 않지만 대부분의 경우 TwelveMonkeys 플러그인을 대신 사용하게 됩니다.
질문: GIF나 PNG와 같은 일반적인 형식은 지원되지 않는 이유는 무엇입니까?
a: 간단히 대답하자면 ImageIO에 내장된 이러한 형식 지원 기능은 있는 그대로 충분하다고 간주된다는 것입니다. Java 7 및 8에서 더 나은 PNG 쓰기 성능을 찾고 있다면 JDK9 PNG Writer Backport를 참조하세요.
Q: 다음 출시는 언제인가요? 현재 출시 일정은 어떻게 되나요?
A: 목표는 버그 수정과 사소한 새로운 기능이 포함된 월별 릴리스를 만드는 것입니다. 그리고 더 많은 "주요" 기능이 포함된 분기별 릴리스도 제공됩니다.
Q: 저는 이 프로젝트를 정말 좋아해요! 어떻게 도와드릴까요?
A: 미해결 문제를 살펴보고 해결하는 데 도움이 될 수 있는 문제가 있는지 확인하거나 샘플 파일을 제공하거나 테스트 사례를 생성하세요. 귀하 또는 귀하의 조직이 GitHub 후원자를 통해 후원자가 되는 것도 가능합니다. 자금을 제공하면 버그 수정과 새로운 기능 구현에 더 많은 시간을 투자할 수 있습니다.
Q: JAI는 어떻습니까? 몇몇 형식은 이미 JAI에서 지원됩니다.
A: JAI(특히 jai-imageio)는 일부 동일한 형식을 지원하지만 JAI에는 몇 가지 중요한 문제가 있습니다. 가장 확실한 것은:
질문: JMagick이나 IM4Java는 어떻습니까? 이미 사용 가능한 것을 사용할 수는 없나요?
a: 다양한 형식을 지원하는 훌륭한 라이브러리가 있지만 ImageMagick 기반 라이브러리는 ImageIO에 비해 몇 가지 단점이 있습니다.
우리가 해냈어