instalar descargar c png libpng

descargar - libpng ubuntu



¿Cómo codificar PNG a búfer usando libpng? (3)

Actualmente estoy usando lo siguiente para escribir un archivo PNG en un archivo:

#include <png.h> #include <stdio.h> #include <stdlib.h> #include <stdint.h> /* Pixels in this bitmap structure are stored as BGR. */ typedef struct _RGBPixel { uint8_t blue; uint8_t green; uint8_t red; } RGBPixel; /* Structure for containing decompressed bitmaps. */ typedef struct _RGBBitmap { RGBPixel *pixels; size_t width; size_t height; size_t bytewidth; uint8_t bytes_per_pixel; } RGBBitmap; /* Returns pixel of bitmap at given point. */ #define RGBPixelAtPoint(image, x, y) / *(((image)->pixels) + (((image)->bytewidth * (y)) / + ((x) * (image)->bytes_per_pixel))) /* Attempts to save PNG to file; returns 0 on success, non-zero on error. */ int save_png_to_file(RGBBitmap *bitmap, const char *path) { FILE *fp = fopen(path, "wb"); png_structp png_ptr = NULL; png_infop info_ptr = NULL; size_t x, y; png_uint_32 bytes_per_row; png_byte **row_pointers = NULL; if (fp == NULL) return -1; /* Initialize the write struct. */ png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (png_ptr == NULL) { fclose(fp); return -1; } /* Initialize the info struct. */ info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { png_destroy_write_struct(&png_ptr, NULL); fclose(fp); return -1; } /* Set up error handling. */ if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_write_struct(&png_ptr, &info_ptr); fclose(fp); return -1; } /* Set image attributes. */ png_set_IHDR(png_ptr, info_ptr, bitmap->width, bitmap->height, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); /* Initialize rows of PNG. */ bytes_per_row = bitmap->width * bitmap->bytes_per_pixel; row_pointers = png_malloc(png_ptr, bitmap->height * sizeof(png_byte *)); for (y = 0; y < bitmap->height; ++y) { uint8_t *row = png_malloc(png_ptr, sizeof(uint8_t) * bitmap->bytes_per_pixel); row_pointers[y] = (png_byte *)row; for (x = 0; x < bitmap->width; ++x) { RGBPixel color = RGBPixelAtPoint(bitmap, x, y); *row++ = color.red; *row++ = color.green; *row++ = color.blue; } } /* Actually write the image data. */ png_init_io(png_ptr, fp); png_set_rows(png_ptr, info_ptr, row_pointers); png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL); /* Cleanup. */ for (y = 0; y < bitmap->height; y++) { png_free(png_ptr, row_pointers[y]); } png_free(png_ptr, row_pointers); /* Finish writing. */ png_destroy_write_struct(&png_ptr, &info_ptr); fclose(fp); return 0; }

¿Cómo puedo escribir una función similar (en C) para codificar un PNG en un búfer en memoria?

El prototipo se vería algo así:

uint8_t *encode_png_to_buffer(RGBBitmap *source);

Y parece que probablemente necesito hacer un uso de png_set_write_fn() .

Pero aparte de eso no estoy seguro de cómo abordar esto. ¿Hay algún ejemplo de esto siendo hecho? Seguramente no soy el primero en necesitar esta funcionalidad.


Encontré una versión anterior de este código y lo piraté para generar y guardar un archivo PNG en escala de grises de 16 bits. Se ejecuta y genera este PNG:

Aquí está la fuente completa y el comando GCC para construir el ejecutable. Se ejecuta en mi sistema, OpenSuse 42/64 con GCC -> gcc versión 4.8.5 (SUSE Linux) Y libpng 1.6.23, pero puede derretir el condensador de flujo si alguien es tan imprudente o imprudente como para intentar ejecutarlo. ;)

#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, encontré que el código simplificado anterior es útil para que funcionen los 16 códigos QBit PNG. Este truco no probado y potencialmente peligroso se agregó para fines de referencia solo con un descargo de responsabilidad sobre los riesgos inherentes de ejecutarlo. La línea de error del compilador se agregó para que alguien tuviera que editarla para compilarla, convirtiéndola en su propia versión personalizada. La publicación puede haber agregado una iota de información útil a un hilo que ya es bueno. Las preguntas puramente filosóficas agregan ruido pero no luz ... ¿Tal vez podrías agregar una característica al código?

NOTA: La primera ejecución tuvo un resultado extraño en la CPU Intel Skylake:

¡Has sido endianeado!

Tuvo que alterar esta línea:

png_write_png(png_ptr,info_ptr, PNG_TRANSFORM_SWAP_ENDIAN,NULL);


Sí, usando png_set_write_fn algo como esto - sin probar:

Actualizado con ediciones de comentario

/* structure to store PNG image bytes */ struct mem_encode { char *buffer; size_t size; } void my_png_write_data(png_structp png_ptr, png_bytep data, png_size_t length) { /* with libpng15 next line causes pointer deference error; use libpng12 */ struct mem_encode* p=(struct mem_encode*)png_get_io_ptr(png_ptr); /* was png_ptr->io_ptr */ size_t nsize = p->size + length; /* allocate or grow buffer */ if(p->buffer) p->buffer = realloc(p->buffer, nsize); else p->buffer = malloc(nsize); if(!p->buffer) png_error(png_ptr, "Write Error"); /* copy new bytes to end of buffer */ memcpy(p->buffer + p->size, data, length); p->size += length; } /* This is optional but included to show how png_set_write_fn() is called */ void my_png_flush(png_structp png_ptr) { } int save_png_to_file(RGBBitmap *bitmap, const char *path) { ... /* static */ struct mem_encode state; /* initialise - put this before png_write_png() call */ state.buffer = NULL; state.size = 0; /* if my_png_flush() is not needed, change the arg to NULL */ png_set_write_fn(png_ptr, &state, my_png_write_data, my_png_flush); ... call png_write_png() ... /* now state.buffer contains the PNG image of size s.size bytes */ /* cleanup */ if(state.buffer) free(state.buffer);


#include <png.h> #include <vector> #include <iostream> #include <stdlib.h> //encode and write PNG to memory (std::vector) with libpng on C++ typedef unsigned char ui8; #define ASSERT_EX(cond, error_message) do { if (!(cond)) { std::cerr << error_message; exit(1);} } while(0) static void PngWriteCallback(png_structp png_ptr, png_bytep data, png_size_t length) { std::vector<ui8> *p = (std::vector<ui8>*)png_get_io_ptr(png_ptr); p->insert(p->end(), data, data + length); } struct TPngDestructor { png_struct *p; TPngDestructor(png_struct *p) : p(p) {} ~TPngDestructor() { if (p) { png_destroy_write_struct(&p, NULL); } } }; void WritePngToMemory(size_t w, size_t h, const ui8 *dataRGBA, std::vector<ui8> *out) { out->clear(); png_structp p = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); ASSERT_EX(p, "png_create_write_struct() failed"); TPngDestructor destroyPng(p); png_infop info_ptr = png_create_info_struct(p); ASSERT_EX(info_ptr, "png_create_info_struct() failed"); ASSERT_EX(0 == setjmp(png_jmpbuf(p)), "setjmp(png_jmpbuf(p) failed"); png_set_IHDR(p, info_ptr, w, h, 8, PNG_COLOR_TYPE_RGBA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); //png_set_compression_level(p, 1); std::vector<ui8*> rows(h); for (size_t y = 0; y < h; ++y) rows[y] = (ui8*)dataRGBA + y * w * 4; png_set_rows(p, info_ptr, &rows[0]); png_set_write_fn(p, out, PngWriteCallback, NULL); png_write_png(p, info_ptr, PNG_TRANSFORM_IDENTITY, NULL); }