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! 54 BPositionIO * 55 get_pio(png_structp ppng) 56 { 57 BPositionIO *pio = NULL; 58 pio = static_cast<BPositionIO *>(png_get_io_ptr(ppng)); 59 return pio; 60 } 61 62 void 63 pngcb_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 69 void 70 pngcb_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 76 void 77 pngcb_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 83 void 84 PrintPNGInfo(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 222 int 223 main(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