Я нашел более раннюю версию этого кода и взломал ее, чтобы сгенерировать и сохранить 16-битный PNG-файл в градациях серого. Он запускает и генерирует этот PNG:
Вот полный исходный код и команда GCC для создания исполняемого файла. Он работает на моей системе, OpenSuse 42/64 с GCC -> gcc версии 4.8.5 (SUSE Linux) И libpng 1.6.23, но может растопить ваш конденсатор потока, если кто-то будет настолько неблагоразумным или наглым, что попытаться его запустить. ;)
#include <png.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include "string.h"
/* 8 QBit RGB/24 to 16 QBit Grayscale hack
* based on code found at
* http://www.lemoda.net/c/write-png/ and png.h libpng version 1.6.23
*/
/*
gcc -L/usr/local/static -I/usr/local/static/include -lpng16 /home/photog/bin/png.test.gray16.c -lm -o /home/photog/bin/png.tg16
*/
// =============================================================================
typedef struct {
uint8_t red; uint8_t green; uint8_t blue; // A colored pixel
} pixel_t;
typedef struct {
uint16_t gray; // A GRAY pixel
} pixel_gray_16_t;
typedef struct { // A picture
pixel_gray_16_t *pixels;
size_t width;
size_t height;
} bitmap_t;
// =============================================================================
// Write "bitmap" to a PNG file specified by "path"; returns 0 on
// success, non-zero on error
static int save_png_to_file (bitmap_t *bitmap, const char *path) {
FILE * fp;
png_structp png_ptr = NULL;
png_infop info_ptr = NULL;
size_t x, y;
int pidx=0; // Pixel_Index
png_byte **row_pointers = NULL; // KLUDGE!!
/* "status" contains the return value of this function. At first
it is set to a value which means 'failure'. When the routine
has finished its work, it is set to a value which means
'success'. */
int status = -1;
/* The following number is set by trial and error only. I cannot
see where it it is documented in the libpng manual */
int pixel_size = 2; // 3 for RGB/24;
int depth = 16; // 8 for RGB/24;
fp = fopen (path, "wb"); if (! fp) { goto fopen_failed; }
png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (png_ptr == NULL) { goto png_create_write_struct_failed; }
info_ptr = png_create_info_struct (png_ptr);
if (info_ptr == NULL) { goto png_create_info_struct_failed; }
/* Set up error handling. */
if (setjmp (png_jmpbuf (png_ptr))) { goto png_failure; }
// Set image attributes; # de fine PNG_COLOR_TYPE_GRAY 0
png_set_IHDR (png_ptr, info_ptr, bitmap->width, bitmap->height, depth,
PNG_COLOR_TYPE_GRAY, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
PNG_FILTER_TYPE_DEFAULT);
/* Initialize rows of PNG. */
row_pointers=png_malloc(png_ptr, bitmap->height * sizeof(png_uint_16 *));
// Copy system Callocated user data to PNG owned space
for (y=0, pidx=0; y < bitmap->height; ++y) {
png_byte *row =
png_malloc(png_ptr, sizeof(uint8_t) * bitmap->width * pixel_size);
row_pointers[y] = row;
memcpy((void *)row, bitmap->pixels+pidx, bitmap->width * 2);
pidx += bitmap->width; // Move to next row
}
/* Write the image data to "fp". */
png_init_io (png_ptr, fp);
png_set_rows (png_ptr, info_ptr, row_pointers);
png_write_png(png_ptr,info_ptr, PNG_TRANSFORM_SWAP_ENDIAN,NULL);
//png_write_png (png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);
// The routine has successfully written the file, so we set "status" to a
// value which indicates success
status = 0;
for(y=0; y < bitmap->height; y++) png_free (png_ptr, row_pointers[y]);
png_free (png_ptr, row_pointers);
png_failure:
png_create_info_struct_failed:
png_destroy_write_struct (&png_ptr, &info_ptr);
png_create_write_struct_failed:
fclose (fp);
fopen_failed:
return status;
}
// =============================================================================
// =============================================================================
int main () {
bitmap_t fruit;
const char ofn[]={ "fruit.g16.png" }; // Output FileName
int x, y, pidx=0;
uint16_t gray_u16;
float graysf; // Gray Scale factor. 0->0, last_pix -> QMax(16)
fruit.width = 400; // Size the image
fruit.height = 400;
graysf=(65535.0f/fruit.width)/fruit.height; // Last pix => 65535
fruit.pixels=calloc(sizeof(pixel_gray_16_t), fruit.width * fruit.height);
// Create linear black -> white gradient
for(y=0; y < fruit.height; y++) {
for(x=0; x < fruit.width; x++) {
gray_u16=(uint16_t)lrintf((y*fruit.width+x)*graysf);
fruit.pixels[pidx++].gray = gray_u16;
}
}
// Write the image to a file
save_png_to_file (&fruit, ofn);
printf("Wrote gray/16 PNG file %s\n", ofn);
return 0;
} this line may not compile
// =============================================================================
groch, я нашел выше, урезанный код, полезный для работы 16-битного кода PNG. Этот непроверенный и потенциально опасный хак был добавлен в справочных целях только с отказом от ответственности за присущие ему риски. Была добавлена строка ошибки компилятора, так что кто-то должен будет отредактировать его для компиляции, сделав его собственной, настроенной версией. Сообщение, возможно, добавило йоту полезной информации к уже хорошей теме. Чисто философские чудеса добавляют шума, но не дают света ... Возможно, вы могли бы добавить функцию в код?
ПРИМЕЧАНИЕ. При первом запуске на процессоре Intel Skylake получился странный результат:
Вы были Endianed!
Пришлось изменить эту строку:
png_write_png(png_ptr,info_ptr, PNG_TRANSFORM_SWAP_ENDIAN,NULL);