1/*****************************************************************************/
2// pnginfo
3// Written by Michael Wilber, Haiku Translation Kit Team
4//
5// Version:
6//
7// pnginfo is a command line program for displaying text information about
8// PNG images.
9//
10// This application and all source files used in its construction, except
11// where noted, are licensed under the MIT License, and have been written
12// and are:
13//
14// Copyright (c) 2004 Haiku Project
15//
16// Permission is hereby granted, free of charge, to any person obtaining a
17// copy of this software and associated documentation files (the "Software"),
18// to deal in the Software without restriction, including without limitation
19// the rights to use, copy, modify, merge, publish, distribute, sublicense,
20// and/or sell copies of the Software, and to permit persons to whom the
21// Software is furnished to do so, subject to the following conditions:
22//
23// The above copyright notice and this permission notice shall be included
24// in all copies or substantial portions of the Software.
25//
26// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
27// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
28// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
29// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
30// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
31// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
32// DEALINGS IN THE SOFTWARE.
33/*****************************************************************************/
34#include <stdio.h>
35#include <stdlib.h>
36#include <string.h>
37#include <png.h>
38#include <ByteOrder.h>
39#include <File.h>
40#include <TranslatorFormats.h>
41#include <StorageDefs.h>
42
43 /* The png_jmpbuf() macro, used in error handling, became available in
44  * libpng version 1.0.6.  If you want to be able to run your code with older
45  * versions of libpng, you must define the macro yourself (but only if it
46  * is not already defined by libpng!).
47  */
48
49#ifndef png_jmpbuf
50#  define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf)
51#endif
52
53//// libpng Callback functions!
54BPositionIO *
55get_pio(png_structp ppng)
56{
57	BPositionIO *pio = NULL;
58	pio = static_cast<BPositionIO *>(png_get_io_ptr(ppng));
59	return pio;
60}
61
62void
63pngcb_read_data(png_structp ppng, png_bytep pdata, png_size_t length)
64{
65	BPositionIO *pio = get_pio(ppng);
66	pio->Read(pdata, static_cast<size_t>(length));
67}
68
69void
70pngcb_write_data(png_structp ppng, png_bytep pdata, png_size_t length)
71{
72	BPositionIO *pio = get_pio(ppng);
73	pio->Write(pdata, static_cast<size_t>(length));
74}
75
76void
77pngcb_flush_data(png_structp ppng)
78{
79	// I don't think I really need to do anything here
80}
81//// End: libpng Callback functions
82
83void
84PrintPNGInfo(const char *path)
85{
86	printf("\n--- %s ---\n", path);
87
88	BFile *pfile;
89	pfile = new BFile(path, B_READ_ONLY);
90	if (!pfile || pfile->InitCheck() != B_OK) {
91		printf("Error: unable to open the file\n");
92		return;
93	}
94	BPositionIO *pio = static_cast<BPositionIO *>(pfile);
95
96	const int32 kSigSize = 8;
97	uint8 buf[kSigSize];
98	if (pio->Read(buf, kSigSize) != kSigSize) {
99		printf("Error: unable to read PNG signature\n");
100		return;
101	}
102	if (!png_check_sig(buf, kSigSize)) {
103		// if first 8 bytes of stream don't match PNG signature bail
104		printf("Error: file doesn't begin with PNG signature\n");
105		return;
106	}
107
108	// use libpng to get info about the file
109	png_structp ppng = NULL;
110	png_infop pinfo = NULL;
111	while (ppng == NULL) {
112		// create PNG read pointer with default error handling routines
113		ppng = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
114		if (!ppng)
115			break;
116		// alocate / init memory for image information
117		pinfo = png_create_info_struct(ppng);
118		if (!pinfo)
119			break;
120		// set error handling
121		if (setjmp(png_jmpbuf(ppng))) {
122			// When an error occurs in libpng, it uses
123			// the longjmp function to continue execution
124			// from this point
125			printf("Error: error in libpng function\n");
126			break;
127		}
128
129		// set read callback function
130		png_set_read_fn(ppng, static_cast<void *>(pio), pngcb_read_data);
131
132		// Read in PNG image info
133		png_set_sig_bytes(ppng, 8);
134		png_read_info(ppng, pinfo);
135
136		png_uint_32 width, height;
137		int bit_depth, color_type, interlace_type, compression_type, filter_type;
138		png_get_IHDR(ppng, pinfo, &width, &height, &bit_depth, &color_type,
139			&interlace_type, &compression_type, &filter_type);
140
141		printf("                   width: %lu\n", width);
142		printf("                  height: %lu\n", height);
143		printf("               row bytes: %lu\n", pinfo->rowbytes);
144		printf("bit depth (bits/channel): %d\n", bit_depth);
145		printf("                channels: %d\n", pinfo->channels);
146		printf("pixel depth (bits/pixel): %d\n", pinfo->pixel_depth);
147		printf("              color type: ");
148		const char *desc = NULL;
149		switch (color_type) {
150			case PNG_COLOR_TYPE_GRAY:
151				desc = "Grayscale";
152				break;
153			case PNG_COLOR_TYPE_PALETTE:
154				desc = "Palette";
155				break;
156			case PNG_COLOR_TYPE_RGB:
157				desc = "RGB";
158				break;
159			case PNG_COLOR_TYPE_RGB_ALPHA:
160				desc = "RGB + Alpha";
161				break;
162			case PNG_COLOR_TYPE_GRAY_ALPHA:
163				desc = "Grayscale + Alpha";
164				break;
165			default:
166				desc = "Unknown";
167				break;
168		}
169		printf("%s (%d)\n", desc, color_type);
170
171		printf("             interlacing: ");
172		switch (interlace_type) {
173			case PNG_INTERLACE_NONE:
174				desc = "None";
175				break;
176			case PNG_INTERLACE_ADAM7:
177				desc = "Adam7";
178				break;
179			default:
180				desc = "Unknown";
181				break;
182		}
183		printf("%s (%d)\n", desc, interlace_type);
184
185		printf("        compression type: ");
186		switch (compression_type) {
187			case PNG_COMPRESSION_TYPE_DEFAULT:
188				desc = "Default: Deflate method 8, 32K window";
189				break;
190			default:
191				desc = "Unknown";
192				break;
193		}
194		printf("%s (%d)\n", desc, compression_type);
195
196		printf("             filter type: ");
197		switch (filter_type) {
198			case PNG_FILTER_TYPE_DEFAULT:
199				desc = "Single row per-byte";
200				break;
201			case PNG_INTRAPIXEL_DIFFERENCING:
202				desc = "Intrapixel Differencing [for MNG files]";
203				break;
204			default:
205				desc = "Unknown";
206				break;
207		}
208		printf("%s (%d)\n", desc, filter_type);
209	}
210	if (ppng) {
211		// free PNG handle / info structures
212		if (!pinfo)
213			png_destroy_read_struct(&ppng, png_infopp_NULL, png_infopp_NULL);
214		else
215			png_destroy_read_struct(&ppng, &pinfo, png_infopp_NULL);
216	}
217
218	delete pfile;
219	pfile = NULL;
220}
221
222int
223main(int argc, char **argv)
224{
225	if (argc == 1) {
226		printf("\npnginfo - reports information about PNG images\n");
227		printf("\nUsage:\n");
228		printf("pnginfo [options] filename.png\n\n");
229	}
230	else {
231		int32 first = 1;
232		for (int32 i = first; i < argc; i++)
233			PrintPNGInfo(argv[i]);
234	}
235
236	printf("\n");
237
238	return 0;
239}
240
241