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