I wrote the following piece of code to generate a black and white PNG image where each pixel has a value of 16 bits (0 = black, 0xFFFF = white). It is a simple 640x480 test image where all the lines are the same and each line on the left has the maximum black that fades to the white going to the right. Since every line is 640 pixels wide I would have expected to see an almost totally black image that reaches a maximum of 640/65535 of white on the right. Instead I get an image that reaches pure white 2 times in correspondence with the values 0x00ff and 0x01ff. This shows that the most significant byte of each pixel is not used by libpng. Can someone tell me where I'm wrong? Thanks to everyone anyway. Bye
System and Compilation details:
System MacBook Pro (Retina, 15 ", end 2013) with OS X 10.11.6
PNG > gcc --version
Configured with: --prefix = / Applications / Xcode.app / Contents / Developer / usr --with-gxx-include-dir = / Applications / Xcode.app / Contents / Developer / Platforms / MacOSX.platform / Developer / SDKs / MacOSX10.12.sdk / usr / include / c ++ / 4.2.1 Apple LLVM version 8.0.0 (clang-800.0.42.1) Target: x86_64-apple-darwin15.6.0 Thread model: posix InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
PNG> gcc -I /opt/X11/include/ -L /opt/X11/lib/ -l png -l z writeTest16bit.c
The generated image (file.png) is:
/* This is the test code upper described */
#include <png.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#define ERROR -1
#define GOTO_ERROR {line = __LINE__; goto error;}
#define width 640
#define height 460
#define bit_depth 16
unsigned short int image[height][width];
void setBitMapImageGray (void);
int main (int argc, char **argv)
{
char *pngFileName = "file.png";
FILE *pngFile = NULL;
png_structp pngStruct = NULL;
png_infop pngInfo = NULL;
int line = __LINE__;
int i;
setBitMapImageGray ();
if (NULL == (pngFile = fopen (pngFileName, "wb"))) GOTO_ERROR;
if (NULL == (pngStruct = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL))) GOTO_ERROR;
if (NULL == (pngInfo = png_create_info_struct (pngStruct))) GOTO_ERROR;
// setting long jump: posponed
png_init_io(pngStruct, pngFile);
png_set_IHDR (pngStruct, pngInfo, width, height, bit_depth,
PNG_COLOR_TYPE_GRAY, PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
png_write_info (pngStruct, pngInfo);
for (i=0; i<height; i++)
png_write_row (pngStruct, (png_const_bytep)&image[i][0]);
png_write_end (pngStruct, NULL);
png_destroy_write_struct (&pngStruct, (png_infopp)NULL);
fclose (pngFile);
return 0;
error:
printf ("Error in line %d\n", line);
if (pngStruct) png_destroy_write_struct (&pngStruct, (png_infopp)NULL);
if (pngFile) fclose (pngFile);
return (ERROR);
}
void setBitMapImageGray (void)
{
int x,y;
unsigned short int const black=0, step=0x10000/width;
for (y=0; y<height; y++)
for (x=0; x<width; x++)
// image[y][x] = 0xFF00;
image[y][x] = x;
}
You are nearly right - it is not ignoring the high byte but you have an endian-ness issue.
Your code works fine if you add png_set_swap()
after png_write_info()
like this:
...
png_set_IHDR (pngStruct, pngInfo, width, height, bit_depth,
PNG_COLOR_TYPE_GRAY, PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
png_write_info(pngStruct, pngInfo);
png_set_swap(pngStruct); // <--- THIS LINE ADDED
...
Keywords: PNG, libpng, 16-bit, 16 bit, greyscale, endian, endianness, byte order, little endian, big-endian, write, image, image processing, C.