int R_SaveAsPng(void *d, int width, int height, unsigned int (*gp)(void *, int, int), int bgr, FILE *fp, unsigned int transparent, int res) { png_structp png_ptr; png_infop info_ptr; unsigned int col, palette[256]; png_color pngpalette[256]; png_bytep pscanline; png_bytep scanline = (png_bytep) calloc((size_t)(4*width),sizeof(png_byte)); png_byte trans[256]; png_color_16 trans_values[1]; int i, j, r, ncols, mid, high, low, withpalette, have_alpha; volatile DECLARESHIFTS; /* Have we enough memory?*/ if (scanline == NULL) return 0; if (fp == NULL) { free(scanline); return 0; } /* Create and initialize the png_struct with the desired error handler * functions. If you want to use the default stderr and longjump method, * you can supply NULL for the last three parameters. We also check that * the library version is compatible with the one used at compile time, * in case we are using dynamically linked libraries. REQUIRED. */ png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (png_ptr == NULL) { free(scanline); return 0; } /* Allocate/initialize the image information data. REQUIRED */ info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { free(scanline); png_destroy_write_struct(&png_ptr, (png_infopp)NULL); return 0; } /* Set error handling. REQUIRED if you aren't supplying your own * error handling functions in the png_create_write_struct() call. */ #if PNG_LIBPNG_VER < 10400 if (setjmp(png_ptr->jmpbuf)) #else if (setjmp(png_jmpbuf(png_ptr))) #endif { /* If we get here, we had a problem writing the file */ free(scanline); png_destroy_write_struct(&png_ptr, &info_ptr); return 0; } png_set_error_fn(png_ptr, NULL, my_png_error, my_png_warning); /* I/O initialization functions is REQUIRED */ png_init_io(png_ptr, fp); /* Have we less than 256 different colors? */ ncols = 0; if(transparent) palette[ncols++] = transparent & 0xFFFFFF; mid = ncols; withpalette = 1; have_alpha = 0; for (i = 0; (i < height) && withpalette ; i++) { for (j = 0; (j < width) && withpalette ; j++) { col = gp(d,i,j); if (GETALPHA(col) < 255) have_alpha = 1; /* binary search the palette: */ low = 0; high = ncols - 1; while (low <= high) { mid = (low + high)/2; if ( col < palette[mid] ) high = mid - 1; else if ( col > palette[mid] ) low = mid + 1; else break; } if (high < low) { /* didn't find colour in palette, insert it: */ if (ncols >= 256) { withpalette = 0; } else { for (r = ncols; r > low; r--) palette[r] = palette[r-1] ; palette[low] = col; ncols ++; } } } } col = gp(d,0,0); //have_alpha &= (transparent == 0); /* Set the image information here. Width and height are up to 2^31, * bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on * the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY, * PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB, * or PNG_COLOR_TYPE_RGB_ALPHA. interlace is either PNG_INTERLACE_NONE or * PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST * currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED */ png_set_IHDR(png_ptr, info_ptr, width, height, 8, withpalette ? PNG_COLOR_TYPE_PALETTE : (have_alpha ? PNG_COLOR_TYPE_RGB_ALPHA : PNG_COLOR_TYPE_RGB), PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); if (withpalette) { for (i = 0; i < ncols ; i++) { col = palette[i]; if(transparent) { trans[i] = (col == transparent) ? 0:255; pngpalette[i].red = GETRED(col); pngpalette[i].green = GETGREEN(col); pngpalette[i].blue = GETBLUE(col); } else { /* PNG needs NON-premultiplied alpha */ int a = GETALPHA(col); trans[i] = a; if(a == 255 || a == 0) { pngpalette[i].red = GETRED(col); pngpalette[i].green = GETGREEN(col); pngpalette[i].blue = GETBLUE(col); } else { pngpalette[i].red = 0.49 + 255.0*GETRED(col)/a; pngpalette[i].green = 0.49 + 255.0*GETGREEN(col)/a; pngpalette[i].blue = 0.49 + 255.0*GETBLUE(col)/a; } } } png_set_PLTE(png_ptr, info_ptr, pngpalette, ncols); if (transparent || have_alpha) png_set_tRNS(png_ptr, info_ptr, trans, ncols, trans_values); } /* Deal with transparency */ if(transparent && !withpalette) { trans_values[0].red = GETRED(transparent); trans_values[0].blue = GETBLUE(transparent); trans_values[0].green = GETGREEN(transparent); png_set_tRNS(png_ptr, info_ptr, trans, ncols, trans_values); } if(res > 0) png_set_pHYs(png_ptr, info_ptr, res/0.0254, res/0.0254, PNG_RESOLUTION_METER); /* Write the file header information. REQUIRED */ png_write_info(png_ptr, info_ptr); /* * Now, write the pixels */ for (i = 0 ; i < height ; i++) { /* Build the scanline */ pscanline = scanline; for (j = 0 ; j < width ; j++) { col = gp(d, i, j); if (withpalette) { /* binary search the palette (the colour must be there): */ low = 0; high = ncols - 1; while (low <= high) { mid = (low + high)/2; if (col < palette[mid]) high = mid - 1; else if (col > palette[mid]) low = mid + 1; else break; } *pscanline++ = mid; } else { if(have_alpha) { /* PNG needs NON-premultiplied alpha */ int a = GETALPHA(col); if(a == 255 || a == 0) { *pscanline++ = GETRED(col) ; *pscanline++ = GETGREEN(col) ; *pscanline++ = GETBLUE(col) ; *pscanline++ = a; } else { *pscanline++ = 0.49 + 255.0*GETRED(col)/a ; *pscanline++ = 0.49 + 255.0*GETGREEN(col)/a ; *pscanline++ = 0.49 + 255.0*GETBLUE(col)/a ; *pscanline++ = a; } } else { *pscanline++ = GETRED(col) ; *pscanline++ = GETGREEN(col) ; *pscanline++ = GETBLUE(col) ; } } } png_write_row(png_ptr, scanline); } /* It is REQUIRED to call this to finish writing the rest of the file */ png_write_end(png_ptr, info_ptr); /* clean up after the write, and free any memory allocated */ free(scanline); png_destroy_write_struct(&png_ptr, &info_ptr); /* that's it */ return 1; }
static void handle_define(char *yyt) { char namebuf[NSIZE]; char args[NARGS][NSIZE]; char mtext[MLEN]; char *p, *q; p = yyt; (void)strcat(p, " "); q = namebuf; GETALPHA(p, q, namebuf+NSIZE-1); if (*p == '(') { /* if "function macro" */ int arg; int inid; char *ids = 0; p++; /* skip '(' */ SKIPWHITE; if (*p == ')') { arg = 0; } else { for (arg = 0; arg < NARGS; ) { q = args[arg]; GETALPHA(p, q, args[arg] + NSIZE - 1); arg++; SKIPWHITE; if (*p == ')') break; if (*p++ != ',') { lexerror("Missing ',' in #define parameter list"); return; } SKIPWHITE; } if (arg == NARGS) { lexerror("Too many macro arguments"); return; } } p++; /* skip ')' */ for (inid = 0, q = mtext; *p; ) { if (isalunum(*p)) { if (!inid) { inid++; ids = p; } } else { if (inid) { size_t l, idlen = p - ids; int n; for (n = 0; n < arg; n++) { l = strlen(args[n]); if (l == idlen && strncmp(args[n], ids, l) == 0) { q -= idlen; *q++ = MARKS; *q++ = n+MARKS+1; break; } } inid = 0; } } *q = *p; if (*p++ == MARKS) *++q = MARKS; if (q < mtext + MLEN - 2) q++; else { lexerror("Macro text too long"); return; } if (!*p && p[-2] == '\\') { q -= 2; refill(); p = yytext; } } *--q = 0; add_define(namebuf, arg, mtext); } else { for (q = mtext; *p; ) { *q = *p++; if (q < mtext + MLEN - 2) q++; else { lexerror("Macro text too long"); return; } if (!*p && p[-2] == '\\') { q -= 2; refill(); p = yytext; } } *--q = 0; add_define(namebuf, -1, mtext); } return; }
int R_SaveAsTIFF(void *d, int width, int height, unsigned int (*gp)(void *, int, int), int bgr, const char *outfile, int res, int compression) { TIFF *out; int sampleperpixel; tsize_t linebytes; unsigned char *buf, *pscanline; unsigned int col, i, j; int have_alpha = 0; DECLARESHIFTS; for (i = 0; i < height; i++) for (j = 0; j < width; j++) { col = gp(d,i,j); if (GETALPHA(col) < 255) { have_alpha = 1; break; } } sampleperpixel = 3 + have_alpha; out = TIFFOpen(outfile, "w"); if (!out) { warning("unable to open TIFF file '%s'", outfile); return 0; } TIFFSetField(out, TIFFTAG_IMAGEWIDTH, width); TIFFSetField(out, TIFFTAG_IMAGELENGTH, height); TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, sampleperpixel); TIFFSetField(out, TIFFTAG_BITSPERSAMPLE, 8); TIFFSetField(out, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT); TIFFSetField(out, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); TIFFSetField(out, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB); #if 0 /* Possible compression values COMPRESSION_NONE = 1; COMPRESSION_CCITTRLE = 2; COMPRESSION_CCITTFAX3 = COMPRESSION_CCITT_T4 = 3; COMPRESSION_CCITTFAX4 = COMPRESSION_CCITT_T6 = 4; COMPRESSION_LZW = 5; COMPRESSION_JPEG = 7; COMPRESSION_DEFLATE = 32946; COMPRESSION_ADOBE_DEFLATE = 8; */ TIFFSetField(out, TIFFTAG_COMPRESSION, COMPRESSION_NONE); #endif if(compression > 1) TIFFSetField(out, TIFFTAG_COMPRESSION, compression); if (res > 0) { TIFFSetField(out, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH); TIFFSetField(out, TIFFTAG_XRESOLUTION, (float) res); TIFFSetField(out, TIFFTAG_YRESOLUTION, (float) res); } linebytes = sampleperpixel * width; if (TIFFScanlineSize(out)) buf =(unsigned char *)_TIFFmalloc(linebytes); else buf = (unsigned char *)_TIFFmalloc(TIFFScanlineSize(out)); for (i = 0; i < height; i++) { pscanline = buf; for(j = 0; j < width; j++) { col = gp(d, i, j); *pscanline++ = GETRED(col) ; *pscanline++ = GETGREEN(col) ; *pscanline++ = GETBLUE(col) ; if(have_alpha) *pscanline++ = GETALPHA(col) ; } TIFFWriteScanline(out, buf, i, 0); } TIFFClose(out); _TIFFfree(buf); return 1; }