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