MINLINE void linearrgb_to_srgb_ushort4(unsigned short srgb[4], const float linear[4]) { srgb[0] = to_srgb_table_lookup(linear[0]); srgb[1] = to_srgb_table_lookup(linear[1]); srgb[2] = to_srgb_table_lookup(linear[2]); srgb[3] = FTOUSHORT(linear[3]); }
MINLINE void linearrgb_to_srgb_ushort4_predivide(unsigned short srgb[4], const float linear[4]) { float alpha, inv_alpha, t; int i; if (linear[3] == 1.0f || linear[3] == 0.0f) { linearrgb_to_srgb_ushort4(srgb, linear); return; } alpha = linear[3]; inv_alpha = 1.0f / alpha; for (i = 0; i < 3; ++i) { t = linear[i] * inv_alpha; srgb[i] = (t < 1.0f) ? (unsigned short) (to_srgb_table_lookup(t) * alpha) : FTOUSHORT(linearrgb_to_srgb(t) * alpha); } srgb[3] = FTOUSHORT(linear[3]); }
int imb_savepng(struct ImBuf *ibuf, const char *name, int flags) { png_structp png_ptr; png_infop info_ptr; unsigned char *pixels = NULL; unsigned char *from, *to; unsigned short *pixels16 = NULL, *to16; float *from_float, from_straight[4]; png_bytepp row_pointers = NULL; int i, bytesperpixel, color_type = PNG_COLOR_TYPE_GRAY; FILE *fp = NULL; int is_16bit = (ibuf->ftype & PNG_16BIT) && ibuf->rect_float; /* use the jpeg quality setting for compression */ int compression; compression = (int)(((float)(ibuf->ftype & 0xff) / 11.1111f)); compression = compression < 0 ? 0 : (compression > 9 ? 9 : compression); /* for prints */ if (flags & IB_mem) name = "<memory>"; bytesperpixel = (ibuf->planes + 7) >> 3; if ((bytesperpixel > 4) || (bytesperpixel == 2)) { printf("imb_savepng: Cunsupported bytes per pixel: %d for file: '%s'\n", bytesperpixel, name); return (0); } png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (png_ptr == NULL) { printf("imb_savepng: Cannot png_create_write_struct for file: '%s'\n", name); return 0; } info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { png_destroy_write_struct(&png_ptr, (png_infopp)NULL); printf("imb_savepng: Cannot png_create_info_struct for file: '%s'\n", name); return 0; } if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_write_struct(&png_ptr, &info_ptr); printf("imb_savepng: Cannot setjmp for file: '%s'\n", name); return 0; } /* copy image data */ if (is_16bit) pixels16 = MEM_mallocN(ibuf->x * ibuf->y * bytesperpixel * sizeof(unsigned short), "png 16bit pixels"); else pixels = MEM_mallocN(ibuf->x * ibuf->y * bytesperpixel * sizeof(unsigned char), "png 8bit pixels"); if (pixels == NULL && pixels16 == NULL) { png_destroy_write_struct(&png_ptr, &info_ptr); printf("imb_savepng: Cannot allocate pixels array of %dx%d, %d bytes per pixel for file: '%s'\n", ibuf->x, ibuf->y, bytesperpixel, name); return 0; } from = (unsigned char *) ibuf->rect; to = pixels; from_float = ibuf->rect_float; to16 = pixels16; switch (bytesperpixel) { case 4: color_type = PNG_COLOR_TYPE_RGBA; if (is_16bit) { for (i = ibuf->x * ibuf->y; i > 0; i--) { premul_to_straight_v4(from_straight, from_float); to16[0] = FTOUSHORT(from_straight[0]); to16[1] = FTOUSHORT(from_straight[1]); to16[2] = FTOUSHORT(from_straight[2]); to16[3] = FTOUSHORT(from_straight[3]); to16 += 4; from_float += 4; } } else { for (i = ibuf->x * ibuf->y; i > 0; i--) { to[0] = from[0]; to[1] = from[1]; to[2] = from[2]; to[3] = from[3]; to += 4; from += 4; } } break; case 3: color_type = PNG_COLOR_TYPE_RGB; if (is_16bit) { for (i = ibuf->x * ibuf->y; i > 0; i--) { premul_to_straight_v4(from_straight, from_float); to16[0] = FTOUSHORT(from_straight[0]); to16[1] = FTOUSHORT(from_straight[1]); to16[2] = FTOUSHORT(from_straight[2]); to16 += 3; from_float += 4; } } else { for (i = ibuf->x * ibuf->y; i > 0; i--) { to[0] = from[0]; to[1] = from[1]; to[2] = from[2]; to += 3; from += 4; } } break; case 1: color_type = PNG_COLOR_TYPE_GRAY; if (is_16bit) { for (i = ibuf->x * ibuf->y; i > 0; i--) { premul_to_straight_v4(from_straight, from_float); to16[0] = FTOUSHORT(from_straight[0]); to16++; from_float += 4; } } else { for (i = ibuf->x * ibuf->y; i > 0; i--) { to[0] = from[0]; to++; from += 4; } } break; } if (flags & IB_mem) { /* create image in memory */ imb_addencodedbufferImBuf(ibuf); ibuf->encodedsize = 0; png_set_write_fn(png_ptr, (png_voidp) ibuf, WriteData, Flush); } else { fp = BLI_fopen(name, "wb"); if (!fp) { png_destroy_write_struct(&png_ptr, &info_ptr); if (pixels) MEM_freeN(pixels); if (pixels16) MEM_freeN(pixels16); printf("imb_savepng: Cannot open file for writing: '%s'\n", name); return 0; } png_init_io(png_ptr, fp); } #if 0 png_set_filter(png_ptr, 0, PNG_FILTER_NONE | PNG_FILTER_VALUE_NONE | PNG_FILTER_SUB | PNG_FILTER_VALUE_SUB | PNG_FILTER_UP | PNG_FILTER_VALUE_UP | PNG_FILTER_AVG | PNG_FILTER_VALUE_AVG | PNG_FILTER_PAETH | PNG_FILTER_VALUE_PAETH | PNG_ALL_FILTERS); #endif png_set_compression_level(png_ptr, compression); /* png image settings */ png_set_IHDR(png_ptr, info_ptr, ibuf->x, ibuf->y, is_16bit ? 16 : 8, color_type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); /* image text info */ if (ibuf->metadata) { png_text *metadata; ImMetaData *iptr; int num_text = 0; iptr = ibuf->metadata; while (iptr) { num_text++; iptr = iptr->next; } metadata = MEM_callocN(num_text * sizeof(png_text), "png_metadata"); iptr = ibuf->metadata; num_text = 0; while (iptr) { metadata[num_text].compression = PNG_TEXT_COMPRESSION_NONE; metadata[num_text].key = iptr->key; metadata[num_text].text = iptr->value; num_text++; iptr = iptr->next; } png_set_text(png_ptr, info_ptr, metadata, num_text); MEM_freeN(metadata); } if (ibuf->ppm[0] > 0.0 && ibuf->ppm[1] > 0.0) { png_set_pHYs(png_ptr, info_ptr, (unsigned int)(ibuf->ppm[0] + 0.5), (unsigned int)(ibuf->ppm[1] + 0.5), PNG_RESOLUTION_METER); } /* write the file header information */ png_write_info(png_ptr, info_ptr); #ifdef __LITTLE_ENDIAN__ png_set_swap(png_ptr); #endif /* allocate memory for an array of row-pointers */ row_pointers = (png_bytepp) MEM_mallocN(ibuf->y * sizeof(png_bytep), "row_pointers"); if (row_pointers == NULL) { printf("imb_savepng: Cannot allocate row-pointers array for file '%s'\n", name); png_destroy_write_struct(&png_ptr, &info_ptr); if (pixels) MEM_freeN(pixels); if (pixels16) MEM_freeN(pixels16); if (fp) { fclose(fp); } return 0; } /* set the individual row-pointers to point at the correct offsets */ if (is_16bit) { for (i = 0; i < ibuf->y; i++) { row_pointers[ibuf->y - 1 - i] = (png_bytep) ((unsigned short *)pixels16 + (i * ibuf->x) * bytesperpixel); } } else { for (i = 0; i < ibuf->y; i++) { row_pointers[ibuf->y - 1 - i] = (png_bytep) ((unsigned char *)pixels + (i * ibuf->x) * bytesperpixel * sizeof(unsigned char)); } } /* write out the entire image data in one call */ png_write_image(png_ptr, row_pointers); /* write the additional chunks to the PNG file (not really needed) */ png_write_end(png_ptr, info_ptr); /* clean up */ if (pixels) MEM_freeN(pixels); if (pixels16) MEM_freeN(pixels16); MEM_freeN(row_pointers); png_destroy_write_struct(&png_ptr, &info_ptr); if (fp) { fflush(fp); fclose(fp); } return(1); }
/* wrap to avoid macro calling functions multiple times */ BLI_INLINE unsigned short ftoshort(float val) { return FTOUSHORT(val); }
int imb_savetiff(ImBuf *ibuf, const char *name, int flags) { TIFF *image = NULL; uint16 samplesperpixel, bitspersample; size_t npixels; unsigned char *pixels = NULL; unsigned char *from = NULL, *to = NULL; unsigned short *pixels16 = NULL, *to16 = NULL; float *fromf = NULL; float xres, yres; int x, y, from_i, to_i, i; /* check for a valid number of bytes per pixel. Like the PNG writer, * the TIFF writer supports 1, 3 or 4 bytes per pixel, corresponding * to gray, RGB, RGBA respectively. */ samplesperpixel = (uint16)((ibuf->planes + 7) >> 3); if ((samplesperpixel > 4) || (samplesperpixel == 2)) { fprintf(stderr, "imb_savetiff: unsupported number of bytes per " "pixel: %d\n", samplesperpixel); return (0); } if ((ibuf->ftype & TIF_16BIT) && ibuf->rect_float) bitspersample = 16; else bitspersample = 8; /* open TIFF file for writing */ if (flags & IB_mem) { /* bork at the creation of a TIFF in memory */ fprintf(stderr, "imb_savetiff: creation of in-memory TIFF files is " "not yet supported.\n"); return (0); } else { /* create image as a file */ #ifdef WIN32 wchar_t *wname = alloc_utf16_from_8(name, 0); image = TIFFOpenW(wname, "w"); free(wname); #else image = TIFFOpen(name, "w"); #endif } if (image == NULL) { fprintf(stderr, "imb_savetiff: could not open TIFF for writing.\n"); return (0); } /* allocate array for pixel data */ npixels = ibuf->x * ibuf->y; if (bitspersample == 16) pixels16 = (unsigned short *)_TIFFmalloc(npixels * samplesperpixel * sizeof(unsigned short)); else pixels = (unsigned char *)_TIFFmalloc(npixels * samplesperpixel * sizeof(unsigned char)); if (pixels == NULL && pixels16 == NULL) { fprintf(stderr, "imb_savetiff: could not allocate pixels array.\n"); TIFFClose(image); return (0); } /* setup pointers */ if (bitspersample == 16) { fromf = ibuf->rect_float; to16 = pixels16; } else { from = (unsigned char *)ibuf->rect; to = pixels; } /* setup samples per pixel */ TIFFSetField(image, TIFFTAG_BITSPERSAMPLE, bitspersample); TIFFSetField(image, TIFFTAG_SAMPLESPERPIXEL, samplesperpixel); if (samplesperpixel == 4) { unsigned short extraSampleTypes[1]; if (bitspersample == 16) extraSampleTypes[0] = EXTRASAMPLE_ASSOCALPHA; else extraSampleTypes[0] = EXTRASAMPLE_UNASSALPHA; /* RGBA images */ TIFFSetField(image, TIFFTAG_EXTRASAMPLES, 1, extraSampleTypes); TIFFSetField(image, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB); } else if (samplesperpixel == 3) { /* RGB images */ TIFFSetField(image, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB); } else if (samplesperpixel == 1) { /* grayscale images, 1 channel */ TIFFSetField(image, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK); } /* copy pixel data. While copying, we flip the image vertically. */ for (x = 0; x < ibuf->x; x++) { for (y = 0; y < ibuf->y; y++) { from_i = 4 * (y * ibuf->x + x); to_i = samplesperpixel * ((ibuf->y - y - 1) * ibuf->x + x); if (pixels16) { /* convert from float source */ float rgb[4]; if (ibuf->float_colorspace) { /* float buffer was managed already, no need in color space conversion */ copy_v3_v3(rgb, &fromf[from_i]); } else { /* standard linear-to-srgb conversion if float buffer wasn't managed */ linearrgb_to_srgb_v3_v3(rgb, &fromf[from_i]); } rgb[3] = fromf[from_i + 3]; for (i = 0; i < samplesperpixel; i++, to_i++) to16[to_i] = FTOUSHORT(rgb[i]); } else { for (i = 0; i < samplesperpixel; i++, to_i++, from_i++) to[to_i] = from[from_i]; } } } /* write the actual TIFF file */ TIFFSetField(image, TIFFTAG_IMAGEWIDTH, ibuf->x); TIFFSetField(image, TIFFTAG_IMAGELENGTH, ibuf->y); TIFFSetField(image, TIFFTAG_ROWSPERSTRIP, ibuf->y); TIFFSetField(image, TIFFTAG_COMPRESSION, COMPRESSION_DEFLATE); TIFFSetField(image, TIFFTAG_FILLORDER, FILLORDER_MSB2LSB); TIFFSetField(image, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); if (ibuf->ppm[0] > 0.0 && ibuf->ppm[1] > 0.0) { xres = (float)(ibuf->ppm[0] * 0.0254); yres = (float)(ibuf->ppm[1] * 0.0254); } else { xres = yres = IMB_DPI_DEFAULT; } TIFFSetField(image, TIFFTAG_XRESOLUTION, xres); TIFFSetField(image, TIFFTAG_YRESOLUTION, yres); TIFFSetField(image, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH); if (TIFFWriteEncodedStrip(image, 0, (bitspersample == 16) ? (unsigned char *)pixels16 : pixels, ibuf->x * ibuf->y * samplesperpixel * bitspersample / 8) == -1) { fprintf(stderr, "imb_savetiff: Could not write encoded TIFF.\n"); TIFFClose(image); if (pixels) _TIFFfree(pixels); if (pixels16) _TIFFfree(pixels16); return (1); } /* close the TIFF file */ TIFFClose(image); if (pixels) _TIFFfree(pixels); if (pixels16) _TIFFfree(pixels16); return (1); }
int imb_savetiff(ImBuf *ibuf, const char *name, int flags) { TIFF *image = NULL; uint16 samplesperpixel, bitspersample; size_t npixels; unsigned char *pixels = NULL; unsigned char *from = NULL, *to = NULL; unsigned short *pixels16 = NULL, *to16 = NULL; float *fromf = NULL; int x, y, from_i, to_i, i; int extraSampleTypes[1] = { EXTRASAMPLE_ASSOCALPHA }; /* check for a valid number of bytes per pixel. Like the PNG writer, * the TIFF writer supports 1, 3 or 4 bytes per pixel, corresponding * to gray, RGB, RGBA respectively. */ samplesperpixel = (uint16)((ibuf->depth + 7) >> 3); if((samplesperpixel > 4) || (samplesperpixel == 2)) { fprintf(stderr, "imb_savetiff: unsupported number of bytes per " "pixel: %d\n", samplesperpixel); return (0); } if((ibuf->ftype & TIF_16BIT) && ibuf->rect_float) bitspersample = 16; else bitspersample = 8; /* open TIFF file for writing */ if(flags & IB_mem) { /* bork at the creation of a TIFF in memory */ fprintf(stderr, "imb_savetiff: creation of in-memory TIFF files is " "not yet supported.\n"); return (0); } else { /* create image as a file */ image = TIFFOpen(name, "w"); } if(image == NULL) { fprintf(stderr, "imb_savetiff: could not open TIFF for writing.\n"); return (0); } /* allocate array for pixel data */ npixels = ibuf->x * ibuf->y; if(bitspersample == 16) pixels16 = (unsigned short*)_TIFFmalloc(npixels * samplesperpixel * sizeof(unsigned short)); else pixels = (unsigned char*)_TIFFmalloc(npixels * samplesperpixel * sizeof(unsigned char)); if(pixels == NULL && pixels16 == NULL) { fprintf(stderr, "imb_savetiff: could not allocate pixels array.\n"); TIFFClose(image); return (0); } /* setup pointers */ if(bitspersample == 16) { fromf = ibuf->rect_float; to16 = pixels16; } else { from = (unsigned char*)ibuf->rect; to = pixels; } /* setup samples per pixel */ TIFFSetField(image, TIFFTAG_BITSPERSAMPLE, bitspersample); TIFFSetField(image, TIFFTAG_SAMPLESPERPIXEL, samplesperpixel); if(samplesperpixel == 4) { /* RGBA images */ TIFFSetField(image, TIFFTAG_EXTRASAMPLES, 1, extraSampleTypes); TIFFSetField(image, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB); } else if(samplesperpixel == 3) { /* RGB images */ TIFFSetField(image, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB); } else if(samplesperpixel == 1) { /* greyscale images, 1 channel */ TIFFSetField(image, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK); } /* copy pixel data. While copying, we flip the image vertically. */ for(x = 0; x < ibuf->x; x++) { for(y = 0; y < ibuf->y; y++) { from_i = 4*(y*ibuf->x+x); to_i = samplesperpixel*((ibuf->y-y-1)*ibuf->x+x); if(pixels16) { /* convert from float source */ float rgb[3]; if (ibuf->profile == IB_PROFILE_LINEAR_RGB) linearrgb_to_srgb_v3_v3(rgb, &fromf[from_i]); else copy_v3_v3(rgb, &fromf[from_i]); to16[to_i+0] = FTOUSHORT(rgb[0]); to16[to_i+1] = FTOUSHORT(rgb[1]); to16[to_i+2] = FTOUSHORT(rgb[2]); to_i += 3; from_i+=3; if (samplesperpixel == 4) { to16[to_i+3] = FTOUSHORT(fromf[from_i+3]); /*to_i++; from_i++;*/ /*unused, set on each loop */ } } else { for(i = 0; i < samplesperpixel; i++, to_i++, from_i++) to[to_i] = from[from_i]; } } } /* write the actual TIFF file */ TIFFSetField(image, TIFFTAG_IMAGEWIDTH, ibuf->x); TIFFSetField(image, TIFFTAG_IMAGELENGTH, ibuf->y); TIFFSetField(image, TIFFTAG_ROWSPERSTRIP, ibuf->y); TIFFSetField(image, TIFFTAG_COMPRESSION, COMPRESSION_DEFLATE); TIFFSetField(image, TIFFTAG_FILLORDER, FILLORDER_MSB2LSB); TIFFSetField(image, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); TIFFSetField(image, TIFFTAG_XRESOLUTION, 150.0); TIFFSetField(image, TIFFTAG_YRESOLUTION, 150.0); TIFFSetField(image, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH); if(TIFFWriteEncodedStrip(image, 0, (bitspersample == 16)? (unsigned char*)pixels16: pixels, ibuf->x*ibuf->y*samplesperpixel*bitspersample/8) == -1) { fprintf(stderr, "imb_savetiff: Could not write encoded TIFF.\n"); TIFFClose(image); if(pixels) _TIFFfree(pixels); if(pixels16) _TIFFfree(pixels16); return (1); } /* close the TIFF file */ TIFFClose(image); if(pixels) _TIFFfree(pixels); if(pixels16) _TIFFfree(pixels16); return (1); }