Add an option for saving/loading DPX with in log color space with

reference black, reference white and gamma.

Added 16 bit TIFF saving.

This needs more work to cleanup code and add 16 bit TIFF reading, but
committing it now so it can be tested.
This commit is contained in:
Brecht Van Lommel 2008-03-10 11:39:37 +00:00
parent 397ece0008
commit 0ec0f2a02f
14 changed files with 173 additions and 71 deletions

View File

@ -1182,6 +1182,9 @@ int BKE_write_ibuf(ImBuf *ibuf, char *name, int imtype, int subimtype, int quali
}
else if ((G.have_libtiff) && (imtype==R_TIFF)) {
ibuf->ftype= TIF;
if(subimtype & R_TIFF_16BIT)
ibuf->ftype |= TIF_16BIT;
}
#ifdef WITH_OPENEXR
else if (imtype==R_OPENEXR || imtype==R_MULTILAYER) {

View File

@ -225,6 +225,10 @@ Scene *add_scene(char *name)
sce->r.simplify_shadowsamples= 16;
sce->r.simplify_aosss= 1.0f;
sce->r.cineonblack= 95;
sce->r.cineonwhite= 685;
sce->r.cineongamma= 1.7f;
sce->toolsettings = MEM_callocN(sizeof(struct ToolSettings),"Tool Settings Struct");
sce->toolsettings->cornertype=1;
sce->toolsettings->degr = 90;
@ -267,7 +271,7 @@ Scene *add_scene(char *name)
sce->r.osa= 8;
sculptdata_init(sce);
/* note; in header_info.c the scene copy happens..., if you add more to renderdata it has to be checked there */
scene_add_render_layer(sce);

View File

@ -7095,6 +7095,12 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
sce->r.simplify_shadowsamples= 16;
sce->r.simplify_aosss= 1.0f;
}
if(sce->r.cineongamma == 0) {
sce->r.cineonblack= 95;
sce->r.cineonwhite= 685;
sce->r.cineongamma= 1.7f;
}
}
for(ntree=main->nodetree.first; ntree; ntree= ntree->id.next)

View File

@ -170,6 +170,7 @@ typedef enum {
#define RADHDR (1 << 24)
#define TIF (1 << 23)
#define TIF_16BIT (1 << 8 )
#define OPENEXR (1 << 22)
#define OPENEXR_HALF (1 << 8 )

View File

@ -42,14 +42,29 @@
#include "MEM_guardedalloc.h"
/* ugly bad level, should be fixed */
#include "DNA_scene_types.h"
#include "BKE_global.h"
static void cineon_conversion_parameters(LogImageByteConversionParameters *params)
{
params->blackPoint = G.scene->r.cineonblack;
params->whitePoint = G.scene->r.cineonwhite;
params->gamma = G.scene->r.cineongamma;
params->doLogarithm = G.scene->r.subimtype & R_CINEON_LOG;
}
static struct ImBuf *imb_load_dpx_cineon(unsigned char *mem, int use_cineon, int size, int flags)
{
LogImageByteConversionParameters conversion;
ImBuf *ibuf;
LogImageFile *image;
int x, y;
unsigned short *row, *upix;
int width, height, depth;
float *frow;
cineon_conversion_parameters(&conversion);
image = logImageOpenFromMem(mem, size, use_cineon);
@ -70,6 +85,8 @@ static struct ImBuf *imb_load_dpx_cineon(unsigned char *mem, int use_cineon, int
return NULL;
}
logImageSetByteConversion(image, &conversion);
ibuf = IMB_allocImBuf(width, height, 32, IB_rectfloat | flags, 0);
row = MEM_mallocN(sizeof(unsigned short)*width*depth, "row in cineon_dpx.c");
@ -107,10 +124,9 @@ static int imb_save_dpx_cineon(ImBuf *buf, char *filename, int use_cineon, int f
int i, j;
int index;
float *fline;
conversion.blackPoint = 95;
conversion.whitePoint = 685;
conversion.gamma = 1;
cineon_conversion_parameters(&conversion);
/*
* Get the drawable for the current image...
*/

View File

@ -350,8 +350,10 @@ cineonGetRowBytes(CineonFile* cineon, unsigned short* row, int y) {
/* extract required pixels */
for (pixelIndex = 0; pixelIndex < numPixels; ++pixelIndex) {
/* row[pixelIndex] = cineon->lut10[cineon->pixelBuffer[pixelIndex]]; */
row[pixelIndex] = cineon->pixelBuffer[pixelIndex] << 6;
if(cineon->params.doLogarithm)
row[pixelIndex] = cineon->lut10_16[cineon->pixelBuffer[pixelIndex]];
else
row[pixelIndex] = cineon->pixelBuffer[pixelIndex] << 6;
}
return 0;
@ -367,8 +369,10 @@ cineonSetRowBytes(CineonFile* cineon, const unsigned short* row, int y) {
/* put new pixels into pixelBuffer */
for (pixelIndex = 0; pixelIndex < numPixels; ++pixelIndex) {
/* cineon->pixelBuffer[pixelIndex] = cineon->lut8[row[pixelIndex]]; */
cineon->pixelBuffer[pixelIndex] = row[pixelIndex] >> 6;
if(cineon->params.doLogarithm)
cineon->pixelBuffer[pixelIndex] = cineon->lut16_16[row[pixelIndex]];
else
cineon->pixelBuffer[pixelIndex] = row[pixelIndex] >> 6;
}
/* pack into longwords */

View File

@ -199,7 +199,7 @@ dumpDpxMainHeader(DpxMainHeader* header) {
#endif
}
static int verbose = 0;
static int verbose = 1;
void
dpxSetVerbose(int verbosity) {
verbose = verbosity;
@ -275,8 +275,10 @@ dpxGetRowBytes(DpxFile* dpx, unsigned short* row, int y) {
/* extract required pixels */
for (pixelIndex = 0; pixelIndex < numPixels; ++pixelIndex) {
/* row[pixelIndex] = dpx->lut10[dpx->pixelBuffer[pixelIndex]]; */
row[pixelIndex] = dpx->pixelBuffer[pixelIndex] << 6;
if(dpx->params.doLogarithm)
row[pixelIndex] = dpx->lut10_16[dpx->pixelBuffer[pixelIndex]];
else
row[pixelIndex] = dpx->pixelBuffer[pixelIndex] << 6;
}
/* save remaining pixels */
@ -316,8 +318,10 @@ dpxSetRowBytes(DpxFile* dpx, const unsigned short* row, int y) {
/* put new pixels into pixelBuffer */
for (pixelIndex = 0; pixelIndex < numPixels; ++pixelIndex) {
/* dpx->pixelBuffer[dpx->pixelBufferUsed + pixelIndex] = dpx->lut8[row[pixelIndex]]; */
dpx->pixelBuffer[dpx->pixelBufferUsed + pixelIndex] = row[pixelIndex] >> 6;
if(dpx->params.doLogarithm)
dpx->pixelBuffer[dpx->pixelBufferUsed + pixelIndex] = dpx->lut16_16[row[pixelIndex]];
else
dpx->pixelBuffer[dpx->pixelBufferUsed + pixelIndex] = row[pixelIndex] >> 6;
}
dpx->pixelBufferUsed += numPixels;

View File

@ -93,6 +93,35 @@ setupLut(LogImageFile *logImage) {
}
}
/* set up the 10 bit to 16 bit and 16 bit to 10 bit tables */
void
setupLut16(LogImageFile *logImage) {
int i;
double f_black;
double scale;
f_black = convertTo(logImage->params.blackPoint, logImage->params.whitePoint, logImage->params.gamma);
scale = 65535.0 / (1.0 - f_black);
for (i = 0; i <= logImage->params.blackPoint; ++i) {
logImage->lut10_16[i] = 0;
}
for (; i < logImage->params.whitePoint; ++i) {
double f_i;
f_i = convertTo(i, logImage->params.whitePoint, logImage->params.gamma);
logImage->lut10_16[i] = (int)rint(scale * (f_i - f_black));
}
for (; i < 1024; ++i) {
logImage->lut10_16[i] = 65535;
}
for (i = 0; i < 65536; ++i) {
double f_i = f_black + (i / 65535.0) * (1.0 - f_black);
logImage->lut16_16[i] = convertFrom(f_i, logImage->params.whitePoint, logImage->params.gamma);
}
}
/* how many longwords to hold this many pixels? */
int
pixelsToLongs(int numPixels) {

View File

@ -71,6 +71,9 @@ struct _Log_Image_File_t_
unsigned char lut10[1024];
unsigned short lut8[256];
unsigned short lut10_16[1024];
unsigned short lut16_16[65536];
/* pixel access functions */
GetRowFn* getRow;
SetRowFn* setRow;
@ -82,6 +85,7 @@ struct _Log_Image_File_t_
};
void setupLut(LogImageFile*);
void setupLut16(LogImageFile*);
int pixelsToLongs(int numPixels);

View File

@ -89,6 +89,7 @@ logImageGetByteConversionDefaults(LogImageByteConversionParameters* params) {
params->gamma = DEFAULT_GAMMA;
params->blackPoint = DEFAULT_BLACK_POINT;
params->whitePoint = DEFAULT_WHITE_POINT;
params->doLogarithm = 0;
return 0;
}
@ -97,6 +98,7 @@ logImageGetByteConversion(const LogImageFile* logImage, LogImageByteConversionPa
params->gamma = logImage->params.gamma;
params->blackPoint = logImage->params.blackPoint;
params->whitePoint = logImage->params.whitePoint;
params->doLogarithm = 0;
return 0;
}
@ -110,7 +112,8 @@ logImageSetByteConversion(LogImageFile* logImage, const LogImageByteConversionPa
logImage->params.gamma = params->gamma;
logImage->params.blackPoint = params->blackPoint;
logImage->params.whitePoint = params->whitePoint;
setupLut(logImage);
logImage->params.doLogarithm = params->doLogarithm;
setupLut16(logImage);
return 0;
}
return 1;

View File

@ -47,6 +47,7 @@ typedef struct {
float gamma;
int blackPoint;
int whitePoint;
int doLogarithm;
} LogImageByteConversionParameters;
/* int functions return 0 for OK */

View File

@ -418,8 +418,6 @@ struct ImBuf *imb_loadtiff(unsigned char *mem, int size, int flags)
return (ibuf);
}
/**
* Saves a TIFF file.
*
@ -435,14 +433,19 @@ struct ImBuf *imb_loadtiff(unsigned char *mem, int size, int flags)
*
* @return: 1 if the function is successful, 0 on failure.
*/
#define FTOUSHORT(f) ((f >= 1.0f-0.5f/65535)? 65535: (f <= 0.0f)? 0: (unsigned short)(f*65535.0f + 0.5f))
short imb_savetiff(struct ImBuf *ibuf, char *name, int flags)
{
TIFF *image = NULL;
uint16 samplesperpixel;
uint16 samplesperpixel, bitspersample;
size_t npixels;
unsigned char *pixels = NULL;
unsigned char *from = NULL, *to = NULL;
int x, y, from_i, to_i;
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,
@ -456,6 +459,11 @@ short imb_savetiff(struct ImBuf *ibuf, char *name, int flags)
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 */
@ -475,67 +483,67 @@ short imb_savetiff(struct ImBuf *ibuf, char *name, int flags)
/* allocate array for pixel data */
npixels = ibuf->x * ibuf->y;
pixels = (unsigned char*)libtiff__TIFFmalloc(npixels *
samplesperpixel * sizeof(unsigned char));
if (pixels == NULL) {
if(ibuf->ftype & TIF_16BIT)
pixels16 = (unsigned short*)libtiff__TIFFmalloc(npixels *
samplesperpixel * sizeof(unsigned short));
else
pixels = (unsigned char*)libtiff__TIFFmalloc(npixels *
samplesperpixel * sizeof(unsigned char));
if (pixels == NULL && pixels16 == NULL) {
fprintf(stderr,
"imb_savetiff: could not allocate pixels array.\n");
libtiff_TIFFClose(image);
return (0);
}
/* copy pixel data. While copying, we flip the image
* vertically. */
from = (unsigned char*)ibuf->rect;
to = pixels;
/* setup pointers */
if(ibuf->ftype & TIF_16BIT) {
fromf = ibuf->rect_float;
to16 = pixels16;
}
else {
from = (unsigned char*)ibuf->rect;
to = pixels;
}
/* setup samples per pixel */
libtiff_TIFFSetField(image, TIFFTAG_BITSPERSAMPLE, bitspersample);
libtiff_TIFFSetField(image, TIFFTAG_SAMPLESPERPIXEL, samplesperpixel);
switch (samplesperpixel) {
case 4: /* RGBA images, 8 bits per channel */
libtiff_TIFFSetField(image, TIFFTAG_EXTRASAMPLES, 1,
extraSampleTypes);
libtiff_TIFFSetField(image, TIFFTAG_BITSPERSAMPLE, 8);
libtiff_TIFFSetField(image, TIFFTAG_PHOTOMETRIC,
PHOTOMETRIC_RGB);
for (x = 0; x < ibuf->x; x++) {
for (y = 0; y < ibuf->y; y++) {
from_i = 4*(y*ibuf->x+x);
to_i = 4*((ibuf->y-y-1)*ibuf->x+x);
to[to_i++] = from[from_i++];
to[to_i++] = from[from_i++];
to[to_i++] = from[from_i++];
to[to_i] = from[from_i];
}
}
break;
case 3: /* RGB images, 8 bits per channel */
libtiff_TIFFSetField(image, TIFFTAG_BITSPERSAMPLE, 8);
libtiff_TIFFSetField(image, TIFFTAG_PHOTOMETRIC,
PHOTOMETRIC_RGB);
for (x = 0; x < ibuf->x; x++) {
for (y = 0; y < ibuf->y; y++) {
from_i = 4*(y*ibuf->x+x);
to_i = 3*((ibuf->y-y-1)*ibuf->x+x);
to[to_i++] = from[from_i++];
to[to_i++] = from[from_i++];
to[to_i] = from[from_i];
}
}
break;
case 1: /* greyscale images, 1 channel with 8 bits */
libtiff_TIFFSetField(image, TIFFTAG_BITSPERSAMPLE, 8);
libtiff_TIFFSetField(image, TIFFTAG_PHOTOMETRIC,
PHOTOMETRIC_MINISBLACK);
for (x = 0; x < ibuf->x; x++) {
for (y = 0; y < ibuf->y; y++) {
from_i = 4*(y*ibuf->x+x);
to_i = 1*((ibuf->y-y-1)*ibuf->x+x);
if(samplesperpixel == 4) {
/* RGBA images */
libtiff_TIFFSetField(image, TIFFTAG_EXTRASAMPLES, 1,
extraSampleTypes);
libtiff_TIFFSetField(image, TIFFTAG_PHOTOMETRIC,
PHOTOMETRIC_RGB);
}
else if(samplesperpixel == 3) {
/* RGB images */
libtiff_TIFFSetField(image, TIFFTAG_PHOTOMETRIC,
PHOTOMETRIC_RGB);
}
else if(samplesperpixel == 1) {
/* greyscale images, 1 channel */
libtiff_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) {
for (i = 0; i < samplesperpixel; i++, to_i++, from_i++)
to16[to_i] = FTOUSHORT(fromf[from_i]);
}
else {
for (i = 0; i < samplesperpixel; i++, to_i++, from_i++)
to[to_i] = from[from_i];
}
}
break;
}
}
/* write the actual TIFF file */
@ -548,8 +556,9 @@ short imb_savetiff(struct ImBuf *ibuf, char *name, int flags)
libtiff_TIFFSetField(image, TIFFTAG_XRESOLUTION, 150.0);
libtiff_TIFFSetField(image, TIFFTAG_YRESOLUTION, 150.0);
libtiff_TIFFSetField(image, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH);
if (libtiff_TIFFWriteEncodedStrip(image, 0, pixels,
ibuf->x*ibuf->y*samplesperpixel) == -1) {
if (libtiff_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");
libtiff_TIFFClose(image);

View File

@ -305,6 +305,10 @@ typedef struct RenderData {
int simplify_shadowsamples;
float simplify_particles;
float simplify_aosss;
/* cineon */
short cineonwhite, cineonblack;
float cineongamma;
} RenderData;
/* control render convert and shading engine */
@ -670,6 +674,8 @@ typedef struct Scene {
#define R_OPENEXR_HALF 1
#define R_OPENEXR_ZBUF 2
#define R_PREVIEW_JPG 4
#define R_CINEON_LOG 8
#define R_TIFF_16BIT 16
/* bake_mode: same as RE_BAKE_xxx defines */
/* bake_flag: */

View File

@ -2552,6 +2552,18 @@ static void render_panel_format(void)
892,yofs,74,20, &G.scene->r.quality, 0, 0, 0, 0, "Set codec settings for OpenEXR");
#endif
} else if (G.scene->r.imtype == R_DPX || G.scene->r.imtype == R_CINEON) {
uiDefButBitS(block, TOG, R_CINEON_LOG, B_REDR, "Log", 892,yofs,74,20, &G.scene->r.subimtype, 0, 0, 0, 0, "Convert to log color space");
if(G.scene->r.subimtype & R_CINEON_LOG) {
uiBlockBeginAlign(block);
uiDefButS(block, NUM, B_NOP, "B", 892,yofs+44,80,20, &G.scene->r.cineonblack, 0, 1024, 0, 0, "Log conversion reference black");
uiDefButS(block, NUM, B_NOP, "W", 972,yofs+44,80,20, &G.scene->r.cineonwhite, 0, 1024, 0, 0, "Log conversion reference white");
uiDefButF(block, NUM, B_NOP, "G", 1052,yofs+44,70,20, &G.scene->r.cineongamma, 0.0f, 10.0f, 1, 2, "Log conversion gamma");
uiBlockEndAlign(block);
}
} else if (G.scene->r.imtype == R_TIFF) {
uiDefButBitS(block, TOG, R_TIFF_16BIT, B_REDR, "16 Bit", 892,yofs,74,20, &G.scene->r.subimtype, 0, 0, 0, 0, "Save 16 bit per channel TIFF");
} else {
if(G.scene->r.quality < 5) G.scene->r.quality = 90; /* restore from openexr */