if (png_sig_cmp(header, 0, 8)) { fprintf(stderr, "error: %s is not a PNG.\n", file_name); fclose(fp); return 0; }
png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) { fprintf(stderr, "error: png_create_read_struct returned 0.\n"); fclose(fp); return 0; }
// create png info struct png_infop info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { fprintf(stderr, "error: png_create_info_struct returned 0.\n"); png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); fclose(fp); return 0; }
// create png info struct png_infop end_info = png_create_info_struct(png_ptr); if (!end_info) { fprintf(stderr, "error: png_create_info_struct returned 0.\n"); png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) NULL); fclose(fp); return 0; }
// the code in this if statement gets called if libpng encounters an error if (setjmp(png_jmpbuf(png_ptr))) { fprintf(stderr, "error from libpng\n"); png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); fclose(fp); return 0; }
// init png reading png_init_io(png_ptr, fp);
// let libpng know you already read the first 8 bytes png_set_sig_bytes(png_ptr, 8);
// read all the info up to the image data png_read_info(png_ptr, info_ptr);
// variables to pass to get info int bit_depth, color_type; png_uint_32 temp_width, temp_height;
// get info about png png_get_IHDR(png_ptr, info_ptr, &temp_width, &temp_height, &bit_depth, &color_type, NULL, NULL, NULL);
if (width){ *width = temp_width; } if (height){ *height = temp_height; }
// Update the png info struct. png_read_update_info(png_ptr, info_ptr);
// Row size in bytes. int rowbytes = png_get_rowbytes(png_ptr, info_ptr);
// glTexImage2d requires rows to be 4-byte aligned rowbytes += 3 - ((rowbytes-1) % 4);
// Allocate the image_data as a big block, to be given to opengl png_byte * image_data; image_data = malloc(rowbytes * temp_height * sizeof(png_byte)+15); if (image_data == NULL) { fprintf(stderr, "error: could not allocate memory for PNG image data\n"); png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); fclose(fp); return 0; }
// row_pointers is for pointing to image_data for reading the png with libpng png_bytep * row_pointers = malloc(temp_height * sizeof(png_bytep)); if (row_pointers == NULL) { fprintf(stderr, "error: could not allocate memory for PNG row pointers\n"); png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); free(image_data); fclose(fp); return 0; }
// set the individual row_pointers to point at the correct offsets of image_data int i; for (i = 0; i < temp_height; i++) { row_pointers[temp_height - 1 - i] = image_data + i * rowbytes; }
// read the png into image_data through row_pointers png_read_image(png_ptr, row_pointers);
Instead of libpng (which is a terrible shit) you could use Cairo: cairo_image_surface_create_from_png(const char *filename); or DevIL: ilLoadImage(char *FileName); or SDL: IMG_Load(const char *file);
Also, loadpng.c is 401 lines of code, while https://github.com/saniv/gfx/blob/master/png.lisp is 243 lines. Using libpng takes more lines than implementing it from scratch. Something really amazing!
Name:
Anonymous2014-08-28 15:15
>>14 +3421 lines for zlib.lisp which is also required.
>>1 There's no comparison between the two of those. The code you've listed for "Good language" is a function call, whereas the code you've listed for "C/C++" is a function definition.
libpng is, indeed, quite difficult to handle, but it is not C or C++. One way to get around its unwieldiness is to call a program that translates PNG to RGB or RGBA and, if necessary, resize the image to fit the pixel width and height your program requires. This can be done easily on POSIX with the use of popen(3) and convert(1):
That is invalid C. When you say "C/C++" do you mean "something that is valid C and C++" or "something that is valid C and/or C++"? If the latter, why not call a spade a spade? :)
typedef struct { FILE *file; int width; int height; unsigned char *data; int data_precision; int num_components; int restart_interval; struct { int id; int h; int v; int t; int td; int ta; } component_info[3]; jpeg_huffman_table_t hac[4]; jpeg_huffman_table_t hdc[4]; int qtable[4][64]; struct { int ss,se; int ah,al; } scan; int dc[3]; int curbit; unsigned char curbyte; } jpeg_file_desc;
int jpeg_readmarkers(); void jpeg_ycbcr2rgb(); void jpeg_decompress();
extern jpeg_file_desc jpeg_file_s;
jpeg_file_desc jpeg_file_s;
int jpeg_read_byte(); int jpeg_read_word(); int jpeg_read_bit(); int jpeg_read_bits(int); int jpeg_bit2int(int bit,int i); int jpeg_huffmancode(jpeg_huffman_table_t *table); void jpeg_idct(float *data);
int jpeg_read_byte() { fread(&jpeg_file_s.curbyte,1,1,jpeg_file_s.file); jpeg_file_s.curbit = 0; return jpeg_file_s.curbyte; }
int jpeg_read_word() { unsigned short i; fread(&i,2,1,jpeg_file_s.file); i = ((i << 8) & 0xFF00) + ((i >> 8) & 0x00FF); return i; }
>>33 Common lisp is horrible tho, why shouldn't I use scheme instead?
Name:
Anonymous2014-08-31 4:20
>>33 Lisp is great, but the identifier names for many common language primitives, standard library procedures/macros are archaic. It makes you feel like you're in the era of COBOL.
Scheme and *gasp* Clojure are better in this regard.
>>34 When you shorten ``Common Lisp'' down to just ``Lisp'' people will get confused about whether you're talking about Common Lisp or Scheme or another dialect of Lisp.
Name:
Anonymous2016-01-21 18:43
Do any scheme implementations even give you access to assembly-level output generation? Maybe Racket?
Name:
Anonymous2016-01-21 19:45
>>46 common lispers are system/sjw style pushers that want to trample over anything else and be the one true way
It makes you feel like you're in the era of COBOL.
You don't have to use the LONG-HYPHENATED-COBOL-NAMES. Common Lisp also has assembly mnemonics (CAR, CDR, LDB, DPB), IBM 704 subroutines (TERPRI), and good old programmers' abbreviations (PAIRLIS, PRINC, PROGN, SXHASH).