001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.commons.imaging;
018
019import java.io.PrintWriter;
020import java.io.StringWriter;
021import java.util.ArrayList;
022import java.util.Collections;
023import java.util.List;
024import java.util.logging.Logger;
025
026/**
027 * ImageInfo represents a collection of basic properties of an image, such as width, height, format, bit depth, etc.
028 */
029public class ImageInfo {
030
031    public enum ColorType {
032        BW("Black and White"), GRAYSCALE("Grayscale"), RGB("RGB"), CMYK("CMYK"), YCbCr("YCbCr"), YCCK("YCCK"), YCC("YCC"), OTHER("Other"), UNKNOWN("Unknown");
033
034        private final String description;
035
036        ColorType(final String description) {
037            this.description = description;
038        }
039
040        @Override
041        public String toString() {
042            return description;
043        }
044    }
045
046    public enum CompressionAlgorithm {
047        UNKNOWN("Unknown"), NONE("None"), LZW("LZW"), PACKBITS("PackBits"), JPEG_TIFF_OBSOLETE("JPEG Obsolete (TIFF only)"), JPEG("JPEG"),
048        RLE("RLE: Run-Length Encoding"), ADAPTIVE_RLE("Adaptive RLE"), PSD("Photoshop"), PNG_FILTER("PNG Filter"),
049        CCITT_GROUP_3("CCITT Group 3 1-Dimensional Modified Huffman run-length encoding."), CCITT_GROUP_4("CCITT Group 4"), CCITT_1D("CCITT 1D"),
050        DEFLATE("DEFLATE (ZIP)");
051
052        private final String description;
053
054        CompressionAlgorithm(final String description) {
055            this.description = description;
056        }
057
058        @Override
059        public String toString() {
060            return description;
061        }
062    }
063
064    private static final Logger LOGGER = Logger.getLogger(ImageInfo.class.getName());
065
066    private final String formatDetails; // version
067
068    private final int bitsPerPixel;
069    private final List<String> comments;
070
071    private final ImageFormat format;
072    private final String formatName;
073    private final int height;
074    private final String mimeType;
075
076    private final int numberOfImages;
077    private final int physicalHeightDpi;
078    private final float physicalHeightInch;
079    private final int physicalWidthDpi;
080    private final float physicalWidthInch;
081    private final int width;
082    private final boolean progressive;
083    private final boolean transparent;
084
085    private final boolean usesPalette;
086
087    private final ColorType colorType;
088
089    private final CompressionAlgorithm compressionAlgorithm;
090
091    public ImageInfo(final String formatDetails, final int bitsPerPixel, final List<String> comments, final ImageFormat format, final String formatName,
092            final int height, final String mimeType, final int numberOfImages, final int physicalHeightDpi, final float physicalHeightInch,
093            final int physicalWidthDpi, final float physicalWidthInch, final int width, final boolean progressive, final boolean transparent,
094            final boolean usesPalette, final ColorType colorType, final CompressionAlgorithm compressionAlgorithm) {
095        this.formatDetails = formatDetails;
096
097        this.bitsPerPixel = bitsPerPixel;
098        this.comments = comments == null ? Collections.emptyList() : Collections.unmodifiableList(comments);
099
100        this.format = format;
101        this.formatName = formatName;
102        this.height = height;
103        this.mimeType = mimeType;
104
105        this.numberOfImages = numberOfImages;
106        this.physicalHeightDpi = physicalHeightDpi;
107        this.physicalHeightInch = physicalHeightInch;
108        this.physicalWidthDpi = physicalWidthDpi;
109        this.physicalWidthInch = physicalWidthInch;
110        this.width = width;
111        this.progressive = progressive;
112
113        this.transparent = transparent;
114        this.usesPalette = usesPalette;
115
116        this.colorType = colorType;
117        this.compressionAlgorithm = compressionAlgorithm;
118    }
119
120    public void dump() {
121        LOGGER.fine(toString());
122    }
123
124    /**
125     * Returns the bits per pixel of the image data.
126     *
127     * @return bits per pixel of the image data.
128     */
129    public int getBitsPerPixel() {
130        return bitsPerPixel;
131    }
132
133    /**
134     * Returns the {@link org.apache.commons.imaging.ImageInfo.ColorType} of the image.
135     *
136     * @return image color type.
137     */
138    public ColorType getColorType() {
139        return colorType;
140    }
141
142    /**
143     * Returns a list of comments from the image file.
144     *
145     * <p>
146     * This is mostly obsolete.
147     * </p>
148     *
149     * @return A list of comments.
150     */
151    public List<String> getComments() {
152        return new ArrayList<>(comments);
153    }
154
155    /**
156     * Returns a description of the compression algorithm, if any.
157     *
158     * @return compression algorithm description.
159     */
160    public CompressionAlgorithm getCompressionAlgorithm() {
161        return compressionAlgorithm;
162    }
163
164    /**
165     * Returns the image file format, ie. ImageFormat.IMAGE_FORMAT_PNG.
166     *
167     * <p>
168     * Returns ImageFormat.IMAGE_FORMAT_UNKNOWN if format is unknown.
169     * </p>
170     *
171     * @return a constant defined in ImageFormat.
172     * @see ImageFormats
173     */
174    public ImageFormat getFormat() {
175        return format;
176    }
177
178    /**
179     * Returns a description of the file format, ie. format version.
180     *
181     * @return file format description.
182     */
183    public String getFormatDetails() {
184        return formatDetails;
185    }
186
187    /**
188     * Returns a string with the name of the image file format.
189     *
190     * @return the name of the image file format.
191     * @see #getFormat()
192     */
193    public String getFormatName() {
194        return formatName;
195    }
196
197    /**
198     * Returns the height of the image in pixels.
199     *
200     * @return image height in pixels.
201     * @see #getWidth()
202     */
203    public int getHeight() {
204        return height;
205    }
206
207    /**
208     * Returns the MIME type of the image.
209     *
210     * @return image MIME type.
211     * @see #getFormat()
212     */
213    public String getMimeType() {
214        return mimeType;
215    }
216
217    /**
218     * Returns the number of images in the file.
219     *
220     * <p>
221     * Applies mostly to GIF and TIFF; reading PSD/Photoshop layers is not supported, and Jpeg/JFIF EXIF thumbnails are not included in this count.
222     * </p>
223     *
224     * @return number of images in the file.
225     */
226    public int getNumberOfImages() {
227        return numberOfImages;
228    }
229
230    /**
231     * Returns horizontal dpi of the image, if available.
232     *
233     * <p>
234     * Applies to TIFF (optional), BMP (always), GIF (constant: 72), Jpeg (optional), PNG (optional), PNM (constant: 72), PSD/Photoshop (constant: 72).
235     * </p>
236     *
237     * @return returns -1 if not present.
238     */
239    public int getPhysicalHeightDpi() {
240        return physicalHeightDpi;
241    }
242
243    /**
244     * Returns physical height of the image in inches, if available.
245     *
246     * <p>
247     * Applies to TIFF (optional), BMP (always), GIF (constant: 72), Jpeg (optional), PNG (optional), PNM (constant: 72), PSD/Photoshop (constant: 72).
248     * </p>
249     *
250     * @return returns -1 if not present.
251     */
252    public float getPhysicalHeightInch() {
253        return physicalHeightInch;
254    }
255
256    /**
257     * Returns vertical dpi of the image, if available.
258     *
259     * <p>
260     * Applies to TIFF (optional), BMP (always), GIF (constant: 72), Jpeg (optional), PNG (optional), PNM (constant: 72), PSD/Photoshop (constant: 72).
261     * </p>
262     *
263     * @return returns -1 if not present.
264     */
265    public int getPhysicalWidthDpi() {
266        return physicalWidthDpi;
267    }
268
269    /**
270     * Returns physical width of the image in inches, if available.
271     *
272     * <p>
273     * Applies to TIFF (optional), BMP (always), GIF (constant: 72), Jpeg (optional), PNG (optional), PNM (constant: 72), PSD/Photoshop (constant: 72).
274     * </p>
275     *
276     * @return returns -1 if not present.
277     */
278    public float getPhysicalWidthInch() {
279        return physicalWidthInch;
280    }
281
282    /**
283     * Returns the width of the image in pixels.
284     *
285     * @return image width in pixels.
286     * @see #getHeight()
287     */
288    public int getWidth() {
289        return width;
290    }
291
292    /**
293     * Returns true if the image is progressive or interlaced.
294     *
295     * @return {@code true} if the image is progressive or interlaced, {@code false} otherwise.
296     */
297    public boolean isProgressive() {
298        return progressive;
299    }
300
301    /**
302     * Returns true if the image has transparency.
303     *
304     * @return {@code true} if the image has transparency, {@code false} otherwise.
305     */
306    public boolean isTransparent() {
307        return transparent;
308    }
309
310    @Override
311    public String toString() {
312        try {
313            final StringWriter sw = new StringWriter();
314            final PrintWriter pw = new PrintWriter(sw);
315
316            toString(pw, "");
317            pw.flush();
318
319            return sw.toString();
320        } catch (final Exception e) {
321            return "Image Data: Error";
322        }
323    }
324
325    public void toString(final PrintWriter pw, final String prefix) {
326        pw.println("Format Details: " + formatDetails);
327
328        pw.println("Bits Per Pixel: " + bitsPerPixel);
329        pw.println("Comments: " + comments.size());
330        for (int i = 0; i < comments.size(); i++) {
331            final String s = comments.get(i);
332            pw.println("\t" + i + ": '" + s + "'");
333
334        }
335        pw.println("Format: " + format.getName());
336        pw.println("Format Name: " + formatName);
337        pw.println("Compression Algorithm: " + compressionAlgorithm);
338        pw.println("Height: " + height);
339        pw.println("MimeType: " + mimeType);
340        pw.println("Number Of Images: " + numberOfImages);
341        pw.println("Physical Height Dpi: " + physicalHeightDpi);
342        pw.println("Physical Height Inch: " + physicalHeightInch);
343        pw.println("Physical Width Dpi: " + physicalWidthDpi);
344        pw.println("Physical Width Inch: " + physicalWidthInch);
345        pw.println("Width: " + width);
346        pw.println("Is Progressive: " + progressive);
347        pw.println("Is Transparent: " + transparent);
348
349        pw.println("Color Type: " + colorType.toString());
350        pw.println("Uses Palette: " + usesPalette);
351
352        pw.flush();
353
354    }
355
356    /**
357     * Returns true if the image uses a palette.
358     *
359     * @return {@code true} if the image uses a palette, {@code false} otherwise.
360     */
361    public boolean usesPalette() {
362        return usesPalette;
363    }
364
365}