#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <png.h>
#include <ByteOrder.h>
#include <File.h>
#include <TranslatorFormats.h>
#include <StorageDefs.h>
#ifndef png_jmpbuf
# define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf)
#endif
BPositionIO *
get_pio(png_structp ppng)
{
BPositionIO *pio = NULL;
pio = static_cast<BPositionIO *>(png_get_io_ptr(ppng));
return pio;
}
void
pngcb_read_data(png_structp ppng, png_bytep pdata, png_size_t length)
{
BPositionIO *pio = get_pio(ppng);
pio->Read(pdata, static_cast<size_t>(length));
}
void
pngcb_write_data(png_structp ppng, png_bytep pdata, png_size_t length)
{
BPositionIO *pio = get_pio(ppng);
pio->Write(pdata, static_cast<size_t>(length));
}
void
pngcb_flush_data(png_structp ppng)
{
}
void
PrintPNGInfo(const char *path)
{
printf("\n--- %s ---\n", path);
BFile *pfile;
pfile = new BFile(path, B_READ_ONLY);
if (!pfile || pfile->InitCheck() != B_OK) {
printf("Error: unable to open the file\n");
return;
}
BPositionIO *pio = static_cast<BPositionIO *>(pfile);
const int32 kSigSize = 8;
uint8 buf[kSigSize];
if (pio->Read(buf, kSigSize) != kSigSize) {
printf("Error: unable to read PNG signature\n");
return;
}
if (!png_check_sig(buf, kSigSize)) {
printf("Error: file doesn't begin with PNG signature\n");
return;
}
png_structp ppng = NULL;
png_infop pinfo = NULL;
while (ppng == NULL) {
ppng = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (!ppng)
break;
pinfo = png_create_info_struct(ppng);
if (!pinfo)
break;
if (setjmp(png_jmpbuf(ppng))) {
printf("Error: error in libpng function\n");
break;
}
png_set_read_fn(ppng, static_cast<void *>(pio), pngcb_read_data);
png_set_sig_bytes(ppng, 8);
png_read_info(ppng, pinfo);
png_uint_32 width, height;
int bit_depth, color_type, interlace_type, compression_type, filter_type;
png_get_IHDR(ppng, pinfo, &width, &height, &bit_depth, &color_type,
&interlace_type, &compression_type, &filter_type);
printf(" width: %lu\n", width);
printf(" height: %lu\n", height);
printf(" row bytes: %lu\n", pinfo->rowbytes);
printf("bit depth (bits/channel): %d\n", bit_depth);
printf(" channels: %d\n", pinfo->channels);
printf("pixel depth (bits/pixel): %d\n", pinfo->pixel_depth);
printf(" color type: ");
const char *desc = NULL;
switch (color_type) {
case PNG_COLOR_TYPE_GRAY:
desc = "Grayscale";
break;
case PNG_COLOR_TYPE_PALETTE:
desc = "Palette";
break;
case PNG_COLOR_TYPE_RGB:
desc = "RGB";
break;
case PNG_COLOR_TYPE_RGB_ALPHA:
desc = "RGB + Alpha";
break;
case PNG_COLOR_TYPE_GRAY_ALPHA:
desc = "Grayscale + Alpha";
break;
default:
desc = "Unknown";
break;
}
printf("%s (%d)\n", desc, color_type);
printf(" interlacing: ");
switch (interlace_type) {
case PNG_INTERLACE_NONE:
desc = "None";
break;
case PNG_INTERLACE_ADAM7:
desc = "Adam7";
break;
default:
desc = "Unknown";
break;
}
printf("%s (%d)\n", desc, interlace_type);
printf(" compression type: ");
switch (compression_type) {
case PNG_COMPRESSION_TYPE_DEFAULT:
desc = "Default: Deflate method 8, 32K window";
break;
default:
desc = "Unknown";
break;
}
printf("%s (%d)\n", desc, compression_type);
printf(" filter type: ");
switch (filter_type) {
case PNG_FILTER_TYPE_DEFAULT:
desc = "Single row per-byte";
break;
case PNG_INTRAPIXEL_DIFFERENCING:
desc = "Intrapixel Differencing [for MNG files]";
break;
default:
desc = "Unknown";
break;
}
printf("%s (%d)\n", desc, filter_type);
}
if (ppng) {
if (!pinfo)
png_destroy_read_struct(&ppng, png_infopp_NULL, png_infopp_NULL);
else
png_destroy_read_struct(&ppng, &pinfo, png_infopp_NULL);
}
delete pfile;
pfile = NULL;
}
int
main(int argc, char **argv)
{
if (argc == 1) {
printf("\npnginfo - reports information about PNG images\n");
printf("\nUsage:\n");
printf("pnginfo [options] filename.png\n\n");
}
else {
int32 first = 1;
for (int32 i = first; i < argc; i++)
PrintPNGInfo(argv[i]);
}
printf("\n");
return 0;
}