This is an automated email from the ASF dual-hosted git repository. ggregory pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/commons-imaging.git
commit c84e13dcf13007a4a70a25ce1ff6657d45aa9969 Author: Gary D. Gregory <garydgreg...@gmail.com> AuthorDate: Sun Apr 27 10:06:44 2025 -0400 Sort members --- .../formats/jpeg/iptc/PhotoshopApp13Data.java | 8 +- .../commons/imaging/formats/png/ChunkType.java | 8 +- .../imaging/formats/png/PngImageMetadata.java | 34 ++++----- .../imaging/formats/png/PngImageParser.java | 88 +++++++++++----------- .../commons/imaging/formats/rgbe/InfoHeader.java | 16 ++-- .../formats/webp/chunks/AbstractWebPChunk.java | 22 +++--- .../imaging/formats/jpeg/iptc/IptcParserTest.java | 40 +++++----- .../commons/imaging/formats/png/PngReadTest.java | 54 ++++++------- 8 files changed, 135 insertions(+), 135 deletions(-) diff --git a/src/main/java/org/apache/commons/imaging/formats/jpeg/iptc/PhotoshopApp13Data.java b/src/main/java/org/apache/commons/imaging/formats/jpeg/iptc/PhotoshopApp13Data.java index d7700b35..2cace63a 100644 --- a/src/main/java/org/apache/commons/imaging/formats/jpeg/iptc/PhotoshopApp13Data.java +++ b/src/main/java/org/apache/commons/imaging/formats/jpeg/iptc/PhotoshopApp13Data.java @@ -26,16 +26,16 @@ public class PhotoshopApp13Data { private final List<IptcRecord> records; private final List<IptcBlock> rawBlocks; + public PhotoshopApp13Data(final List<IptcRecord> records, final List<IptcBlock> rawBlocks) { + this(records, rawBlocks, false); + } + public PhotoshopApp13Data(final List<IptcRecord> records, final List<IptcBlock> rawBlocks, final boolean forceUtf8Encoding) { this.rawBlocks = rawBlocks == null ? Collections.emptyList() : Collections.unmodifiableList(rawBlocks); this.records = records == null ? Collections.emptyList() : Collections.unmodifiableList(records); this.forceUtf8Encoding = forceUtf8Encoding; } - public PhotoshopApp13Data(final List<IptcRecord> records, final List<IptcBlock> rawBlocks) { - this(records, rawBlocks, false); - } - public List<IptcBlock> getNonIptcBlocks() { final List<IptcBlock> result = new ArrayList<>(); for (final IptcBlock block : rawBlocks) { diff --git a/src/main/java/org/apache/commons/imaging/formats/png/ChunkType.java b/src/main/java/org/apache/commons/imaging/formats/png/ChunkType.java index 0980c1e6..2dbb11d6 100644 --- a/src/main/java/org/apache/commons/imaging/formats/png/ChunkType.java +++ b/src/main/java/org/apache/commons/imaging/formats/png/ChunkType.java @@ -214,14 +214,14 @@ public enum ChunkType { this(null, null); } - ChunkType(final Extension extension) { - this(extension, null); - } - ChunkType(final ChunkConstructor constructor) { this(null, constructor); } + ChunkType(final Extension extension) { + this(extension, null); + } + ChunkType(final Extension extension, final ChunkConstructor constructor) { final char[] chars = name().toCharArray(); this.array = name().getBytes(StandardCharsets.UTF_8); diff --git a/src/main/java/org/apache/commons/imaging/formats/png/PngImageMetadata.java b/src/main/java/org/apache/commons/imaging/formats/png/PngImageMetadata.java index 9a77a7b9..a3d2823f 100644 --- a/src/main/java/org/apache/commons/imaging/formats/png/PngImageMetadata.java +++ b/src/main/java/org/apache/commons/imaging/formats/png/PngImageMetadata.java @@ -43,14 +43,29 @@ public class PngImageMetadata implements ImageMetadata { this.exif = exif; } - public ImageMetadata getTextualInformation() { - return textualInformation; + public void dump() { + Debug.debug(this.toString()); } public TiffImageMetadata getExif() { return exif; } + @Override + public List<? extends ImageMetadataItem> getItems() { + if (exif == null) { + return textualInformation.getItems(); + } + + final ArrayList<ImageMetadataItem> result = new ArrayList<>(textualInformation.getItems()); + result.addAll(exif.getItems()); + return result; + } + + public ImageMetadata getTextualInformation() { + return textualInformation; + } + @Override public String toString() { return toString(null); @@ -79,19 +94,4 @@ public class PngImageMetadata implements ImageMetadata { return result.toString(); } - - @Override - public List<? extends ImageMetadataItem> getItems() { - if (exif == null) { - return textualInformation.getItems(); - } - - final ArrayList<ImageMetadataItem> result = new ArrayList<>(textualInformation.getItems()); - result.addAll(exif.getItems()); - return result; - } - - public void dump() { - Debug.debug(this.toString()); - } } diff --git a/src/main/java/org/apache/commons/imaging/formats/png/PngImageParser.java b/src/main/java/org/apache/commons/imaging/formats/png/PngImageParser.java index 897c6351..7eddf966 100644 --- a/src/main/java/org/apache/commons/imaging/formats/png/PngImageParser.java +++ b/src/main/java/org/apache/commons/imaging/formats/png/PngImageParser.java @@ -346,6 +346,50 @@ public class PngImageParser extends AbstractImageParser<PngImagingParameters> im return new PngImagingParameters(); } + /** + * Gets TIFF image metadata for a byte source and TIFF parameters. + * + * @param byteSource The source of the image. + * @param params Optional instructions for special-handling or interpretation of the input data (null objects are permitted and must be supported by + * implementations). + * @return TIFF image metadata. + * @throws ImagingException In the event that the specified content does not conform to the format of the specific parser implementation. + * @throws IOException In the event of unsuccessful data read operation. + * @since 1.0-alpha6 + */ + public TiffImageMetadata getExifMetadata(final ByteSource byteSource, TiffImagingParameters params) + throws ImagingException, IOException { + final byte[] bytes = getExifRawData(byteSource); + if (null == bytes) { + return null; + } + + if (params == null) { + params = new TiffImagingParameters(); + } + + return (TiffImageMetadata) new TiffImageParser().getMetadata(bytes, params); + } + + /** + * Gets TIFF image metadata for a byte source. + * + * @param byteSource The source of the image. + * @return TIFF image metadata. + * @throws ImagingException In the event that the specified content does not conform to the format of the specific parser implementation. + * @throws IOException In the event of unsuccessful data read operation. + * @since 1.0-alpha6 + */ + public byte[] getExifRawData(final ByteSource byteSource) throws ImagingException, IOException { + final List<PngChunk> chunks = readChunks(byteSource, new ChunkType[] { ChunkType.eXIf }, true); + + if (chunks.isEmpty()) { + return null; + } + + return chunks.get(0).getBytes(); + } + @Override public byte[] getIccProfileBytes(final ByteSource byteSource, final PngImagingParameters params) throws ImagingException, IOException { final List<PngChunk> chunks = readChunks(byteSource, new ChunkType[] { ChunkType.iCCP }, true); @@ -547,50 +591,6 @@ public class PngImageParser extends AbstractImageParser<PngImagingParameters> im return new PngImageMetadata(textual, exif); } - /** - * Gets TIFF image metadata for a byte source and TIFF parameters. - * - * @param byteSource The source of the image. - * @param params Optional instructions for special-handling or interpretation of the input data (null objects are permitted and must be supported by - * implementations). - * @return TIFF image metadata. - * @throws ImagingException In the event that the specified content does not conform to the format of the specific parser implementation. - * @throws IOException In the event of unsuccessful data read operation. - * @since 1.0-alpha6 - */ - public TiffImageMetadata getExifMetadata(final ByteSource byteSource, TiffImagingParameters params) - throws ImagingException, IOException { - final byte[] bytes = getExifRawData(byteSource); - if (null == bytes) { - return null; - } - - if (params == null) { - params = new TiffImagingParameters(); - } - - return (TiffImageMetadata) new TiffImageParser().getMetadata(bytes, params); - } - - /** - * Gets TIFF image metadata for a byte source. - * - * @param byteSource The source of the image. - * @return TIFF image metadata. - * @throws ImagingException In the event that the specified content does not conform to the format of the specific parser implementation. - * @throws IOException In the event of unsuccessful data read operation. - * @since 1.0-alpha6 - */ - public byte[] getExifRawData(final ByteSource byteSource) throws ImagingException, IOException { - final List<PngChunk> chunks = readChunks(byteSource, new ChunkType[] { ChunkType.eXIf }, true); - - if (chunks.isEmpty()) { - return null; - } - - return chunks.get(0).getBytes(); - } - @Override public String getName() { return "Png-Custom"; diff --git a/src/main/java/org/apache/commons/imaging/formats/rgbe/InfoHeader.java b/src/main/java/org/apache/commons/imaging/formats/rgbe/InfoHeader.java index ae729c24..99f9098f 100644 --- a/src/main/java/org/apache/commons/imaging/formats/rgbe/InfoHeader.java +++ b/src/main/java/org/apache/commons/imaging/formats/rgbe/InfoHeader.java @@ -30,14 +30,6 @@ final class InfoHeader { this.is = is; } - private char readChar() throws IOException { - final int result = is.read(); - if (result < 0) { - throw new ImagingException("HDR: Unexpected EOF"); - } - return (char) result; - } - String line() throws IOException { final StringBuilder buffer = new StringBuilder(); char c; @@ -46,4 +38,12 @@ final class InfoHeader { } return buffer.toString(); } + + private char readChar() throws IOException { + final int result = is.read(); + if (result < 0) { + throw new ImagingException("HDR: Unexpected EOF"); + } + return (char) result; + } } diff --git a/src/main/java/org/apache/commons/imaging/formats/webp/chunks/AbstractWebPChunk.java b/src/main/java/org/apache/commons/imaging/formats/webp/chunks/AbstractWebPChunk.java index 4a9d3a54..31ea7a3e 100644 --- a/src/main/java/org/apache/commons/imaging/formats/webp/chunks/AbstractWebPChunk.java +++ b/src/main/java/org/apache/commons/imaging/formats/webp/chunks/AbstractWebPChunk.java @@ -45,17 +45,6 @@ public abstract class AbstractWebPChunk extends BinaryFileParser { protected final byte[] bytes; private final int chunkSize; - private AbstractWebPChunk(final int type, final int size, final byte[] bytes, final boolean ignored) { - super(ByteOrder.LITTLE_ENDIAN); - this.type = type; - this.size = bytes.length; - this.bytes = bytes; - // if chunk size is odd, a single padding byte is added - final int padding = size % 2 != 0 ? 1 : 0; - // Chunk FourCC (4 bytes) + Chunk Size (4 bytes) + Chunk Payload (n bytes) + Padding - this.chunkSize = SafeOperations.add(4, 4, size, padding); - } - /** * Create a new WebP chunk. * @@ -68,6 +57,17 @@ public abstract class AbstractWebPChunk extends BinaryFileParser { this(type, size, bytes, checkArgs(size, bytes)); } + private AbstractWebPChunk(final int type, final int size, final byte[] bytes, final boolean ignored) { + super(ByteOrder.LITTLE_ENDIAN); + this.type = type; + this.size = bytes.length; + this.bytes = bytes; + // if chunk size is odd, a single padding byte is added + final int padding = size % 2 != 0 ? 1 : 0; + // Chunk FourCC (4 bytes) + Chunk Size (4 bytes) + Chunk Payload (n bytes) + Padding + this.chunkSize = SafeOperations.add(4, 4, size, padding); + } + /** * Print the chunk to the given stream. * diff --git a/src/test/java/org/apache/commons/imaging/formats/jpeg/iptc/IptcParserTest.java b/src/test/java/org/apache/commons/imaging/formats/jpeg/iptc/IptcParserTest.java index fae09493..e3203809 100644 --- a/src/test/java/org/apache/commons/imaging/formats/jpeg/iptc/IptcParserTest.java +++ b/src/test/java/org/apache/commons/imaging/formats/jpeg/iptc/IptcParserTest.java @@ -48,26 +48,6 @@ import org.junit.jupiter.params.provider.CsvSource; */ public class IptcParserTest { - /** - * Tests for IptcParser encoding support. See IMAGING-168 and pull request #124 for more. - * - * @throws IOException when reading input - * @throws ImagingException when parsing file - */ - @Test - public void testEncodingSupport() throws IOException, ImagingException { - // NOTE: We use the JpegParser, so it will send only the block/segment that IptcParser needs for the test image - final File file = TestResources.resourceToFile("/images/jpeg/iptc/IMAGING-168/111083453-c07f1880-851e-11eb-8b61-2757f7d934bf.jpg"); - final JpegImageParser parser = new JpegImageParser(); - final JpegImageMetadata metadata = (JpegImageMetadata) parser.getMetadata(file); - final JpegPhotoshopMetadata photoshopMetadata = metadata.getPhotoshop(); - @SuppressWarnings("unchecked") - final List<GenericImageMetadataItem> items = (List<GenericImageMetadataItem>) photoshopMetadata.getItems(); - final GenericImageMetadataItem thanksInMandarin = items.get(3); - // converted the thank-you in chinese characters to unicode for comparison here - assertArrayEquals("\u8c22\u8c22".getBytes(StandardCharsets.UTF_8), thanksInMandarin.getText().getBytes(StandardCharsets.UTF_8)); - } - /** * Tests the correct encoding when writing IptcRecords with method {@link IptcParser#writeIptcBlock(List, boolean)}. * <p> @@ -138,6 +118,26 @@ public class IptcParserTest { assertArrayEquals(applicationRecord, actualApplicationRecord); } + /** + * Tests for IptcParser encoding support. See IMAGING-168 and pull request #124 for more. + * + * @throws IOException when reading input + * @throws ImagingException when parsing file + */ + @Test + public void testEncodingSupport() throws IOException, ImagingException { + // NOTE: We use the JpegParser, so it will send only the block/segment that IptcParser needs for the test image + final File file = TestResources.resourceToFile("/images/jpeg/iptc/IMAGING-168/111083453-c07f1880-851e-11eb-8b61-2757f7d934bf.jpg"); + final JpegImageParser parser = new JpegImageParser(); + final JpegImageMetadata metadata = (JpegImageMetadata) parser.getMetadata(file); + final JpegPhotoshopMetadata photoshopMetadata = metadata.getPhotoshop(); + @SuppressWarnings("unchecked") + final List<GenericImageMetadataItem> items = (List<GenericImageMetadataItem>) photoshopMetadata.getItems(); + final GenericImageMetadataItem thanksInMandarin = items.get(3); + // converted the thank-you in chinese characters to unicode for comparison here + assertArrayEquals("\u8c22\u8c22".getBytes(StandardCharsets.UTF_8), thanksInMandarin.getText().getBytes(StandardCharsets.UTF_8)); + } + /** * Some block types (or Image Resource Blocks in Photoshop specification) have a recommendation to not be interpreted by parsers, as they are handled by * Photoshop in a special way, that varies by platform (e.g. Mac, Windows, etc). diff --git a/src/test/java/org/apache/commons/imaging/formats/png/PngReadTest.java b/src/test/java/org/apache/commons/imaging/formats/png/PngReadTest.java index 3a39a62b..95aaf22f 100644 --- a/src/test/java/org/apache/commons/imaging/formats/png/PngReadTest.java +++ b/src/test/java/org/apache/commons/imaging/formats/png/PngReadTest.java @@ -72,6 +72,33 @@ public class PngReadTest extends AbstractPngTest { } } + /** + * Test reading EXIF from the 'eXIf' chunk in PNG file. + * + * @throws IOException if it fails to read the test image + * @throws ImagingException if it fails to read the test image + */ + @Test + public void testReadExif() throws IOException, ImagingException { + final String input = "/images/png/IMAGING-340/image-with-exif.png"; + final String file = PngReadTest.class.getResource(input).getFile(); + final PngImageParser parser = new PngImageParser(); + + final PngImageMetadata pngMetadata = (PngImageMetadata) parser.getMetadata(new File(file)); + + final TiffImageMetadata exifMetadata = pngMetadata.getExif(); + assertEquals("Glavo", + exifMetadata.findDirectory(TiffDirectoryConstants.DIRECTORY_TYPE_ROOT) + .getFieldValue(TiffTagConstants.TIFF_TAG_IMAGE_DESCRIPTION)); + + final PngImageMetadata metadata = (PngImageMetadata) parser.getMetadata(new File(file)); + assertTrue(metadata.getTextualInformation().getItems().isEmpty()); + assertEquals("Glavo", + metadata.getExif() + .findDirectory(TiffDirectoryConstants.DIRECTORY_TYPE_ROOT) + .getFieldValue(TiffTagConstants.TIFF_TAG_IMAGE_DESCRIPTION)); + } + /** * Test reading metadata from PNG file with UTF-8 characters in the text chunks. * @@ -125,31 +152,4 @@ public class PngReadTest extends AbstractPngTest { final PngImageParser parser = new PngImageParser(); assertThrows(ImagingException.class, () -> parser.getBufferedImage(ByteSource.file(file), new PngImagingParameters())); } - - /** - * Test reading EXIF from the 'eXIf' chunk in PNG file. - * - * @throws IOException if it fails to read the test image - * @throws ImagingException if it fails to read the test image - */ - @Test - public void testReadExif() throws IOException, ImagingException { - final String input = "/images/png/IMAGING-340/image-with-exif.png"; - final String file = PngReadTest.class.getResource(input).getFile(); - final PngImageParser parser = new PngImageParser(); - - final PngImageMetadata pngMetadata = (PngImageMetadata) parser.getMetadata(new File(file)); - - final TiffImageMetadata exifMetadata = pngMetadata.getExif(); - assertEquals("Glavo", - exifMetadata.findDirectory(TiffDirectoryConstants.DIRECTORY_TYPE_ROOT) - .getFieldValue(TiffTagConstants.TIFF_TAG_IMAGE_DESCRIPTION)); - - final PngImageMetadata metadata = (PngImageMetadata) parser.getMetadata(new File(file)); - assertTrue(metadata.getTextualInformation().getItems().isEmpty()); - assertEquals("Glavo", - metadata.getExif() - .findDirectory(TiffDirectoryConstants.DIRECTORY_TYPE_ROOT) - .getFieldValue(TiffTagConstants.TIFF_TAG_IMAGE_DESCRIPTION)); - } }