diff options
Diffstat (limited to 'source/blender/imbuf/intern/radiance_hdr.c')
-rw-r--r-- | source/blender/imbuf/intern/radiance_hdr.c | 639 |
1 files changed, 333 insertions, 306 deletions
diff --git a/source/blender/imbuf/intern/radiance_hdr.c b/source/blender/imbuf/intern/radiance_hdr.c index dce61953432..e3ab460cce4 100644 --- a/source/blender/imbuf/intern/radiance_hdr.c +++ b/source/blender/imbuf/intern/radiance_hdr.c @@ -48,7 +48,7 @@ /* needed constants */ #define MINELEN 8 #define MAXELEN 0x7fff -#define MINRUN 4 /* minimum run length */ +#define MINRUN 4 /* minimum run length */ #define RED 0 #define GRN 1 #define BLU 2 @@ -58,98 +58,105 @@ typedef unsigned char RGBE[4]; typedef float fCOLOR[3]; /* copy source -> dest */ -#define COPY_RGBE(c1, c2) (c2[RED] = c1[RED], c2[GRN] = c1[GRN], c2[BLU] = c1[BLU], c2[EXP] = c1[EXP]) +#define COPY_RGBE(c1, c2) \ + (c2[RED] = c1[RED], c2[GRN] = c1[GRN], c2[BLU] = c1[BLU], c2[EXP] = c1[EXP]) /* read routines */ -static const unsigned char *oldreadcolrs(RGBE *scan, const unsigned char *mem, int xmax, const unsigned char *mem_eof) +static const unsigned char *oldreadcolrs(RGBE *scan, + const unsigned char *mem, + int xmax, + const unsigned char *mem_eof) { - size_t i, rshift = 0, len = xmax; - while (len > 0) { - if (UNLIKELY(mem_eof - mem < 4)) { - return NULL; - } - scan[0][RED] = *mem++; - scan[0][GRN] = *mem++; - scan[0][BLU] = *mem++; - scan[0][EXP] = *mem++; - if (scan[0][RED] == 1 && scan[0][GRN] == 1 && scan[0][BLU] == 1) { - for (i = scan[0][EXP] << rshift; i > 0; i--) { - COPY_RGBE(scan[-1], scan[0]); - scan++; - len--; - } - rshift += 8; - } - else { - scan++; - len--; - rshift = 0; - } - } - return mem; + size_t i, rshift = 0, len = xmax; + while (len > 0) { + if (UNLIKELY(mem_eof - mem < 4)) { + return NULL; + } + scan[0][RED] = *mem++; + scan[0][GRN] = *mem++; + scan[0][BLU] = *mem++; + scan[0][EXP] = *mem++; + if (scan[0][RED] == 1 && scan[0][GRN] == 1 && scan[0][BLU] == 1) { + for (i = scan[0][EXP] << rshift; i > 0; i--) { + COPY_RGBE(scan[-1], scan[0]); + scan++; + len--; + } + rshift += 8; + } + else { + scan++; + len--; + rshift = 0; + } + } + return mem; } -static const unsigned char *freadcolrs(RGBE *scan, const unsigned char *mem, int xmax, const unsigned char *mem_eof) +static const unsigned char *freadcolrs(RGBE *scan, + const unsigned char *mem, + int xmax, + const unsigned char *mem_eof) { - if (UNLIKELY(mem_eof - mem < 4)) { - return NULL; - } - - if (UNLIKELY((xmax < MINELEN) | (xmax > MAXELEN))) { - return oldreadcolrs(scan, mem, xmax, mem_eof); - } - - int val = *mem++; - if (val != 2) { - return oldreadcolrs(scan, mem - 1, xmax, mem_eof); - } - - scan[0][GRN] = *mem++; - scan[0][BLU] = *mem++; - - val = *mem++; - - if (scan[0][GRN] != 2 || scan[0][BLU] & 128) { - scan[0][RED] = 2; - scan[0][EXP] = val; - return oldreadcolrs(scan + 1, mem, xmax - 1, mem_eof); - } - - if (UNLIKELY(((scan[0][BLU] << 8) | val) != xmax)) { - return NULL; - } - - for (size_t i = 0; i < 4; i++) { - if (UNLIKELY(mem_eof - mem < 2)) { - return NULL; - } - for (size_t j = 0; j < xmax; ) { - int code = *mem++; - if (code > 128) { - code &= 127; - if (UNLIKELY(code + j > xmax)) { - return NULL; - } - val = *mem++; - while (code--) { - scan[j++][i] = (unsigned char)val; - } - } - else { - if (UNLIKELY(mem_eof - mem < code)) { - return NULL; - } - if (UNLIKELY(code + j > xmax)) { - return NULL; - } - while (code--) { - scan[j++][i] = *mem++; - } - } - } - } - - return mem; + if (UNLIKELY(mem_eof - mem < 4)) { + return NULL; + } + + if (UNLIKELY((xmax < MINELEN) | (xmax > MAXELEN))) { + return oldreadcolrs(scan, mem, xmax, mem_eof); + } + + int val = *mem++; + if (val != 2) { + return oldreadcolrs(scan, mem - 1, xmax, mem_eof); + } + + scan[0][GRN] = *mem++; + scan[0][BLU] = *mem++; + + val = *mem++; + + if (scan[0][GRN] != 2 || scan[0][BLU] & 128) { + scan[0][RED] = 2; + scan[0][EXP] = val; + return oldreadcolrs(scan + 1, mem, xmax - 1, mem_eof); + } + + if (UNLIKELY(((scan[0][BLU] << 8) | val) != xmax)) { + return NULL; + } + + for (size_t i = 0; i < 4; i++) { + if (UNLIKELY(mem_eof - mem < 2)) { + return NULL; + } + for (size_t j = 0; j < xmax;) { + int code = *mem++; + if (code > 128) { + code &= 127; + if (UNLIKELY(code + j > xmax)) { + return NULL; + } + val = *mem++; + while (code--) { + scan[j++][i] = (unsigned char)val; + } + } + else { + if (UNLIKELY(mem_eof - mem < code)) { + return NULL; + } + if (UNLIKELY(code + j > xmax)) { + return NULL; + } + while (code--) { + scan[j++][i] = *mem++; + } + } + } + } + + return mem; } /* helper functions */ @@ -157,250 +164,270 @@ static const unsigned char *freadcolrs(RGBE *scan, const unsigned char *mem, int /* rgbe -> float color */ static void RGBE2FLOAT(RGBE rgbe, fCOLOR fcol) { - if (rgbe[EXP] == 0) { - fcol[RED] = fcol[GRN] = fcol[BLU] = 0; - } - else { - float f = ldexp(1.0, rgbe[EXP] - (COLXS + 8)); - fcol[RED] = f * (rgbe[RED] + 0.5f); - fcol[GRN] = f * (rgbe[GRN] + 0.5f); - fcol[BLU] = f * (rgbe[BLU] + 0.5f); - } + if (rgbe[EXP] == 0) { + fcol[RED] = fcol[GRN] = fcol[BLU] = 0; + } + else { + float f = ldexp(1.0, rgbe[EXP] - (COLXS + 8)); + fcol[RED] = f * (rgbe[RED] + 0.5f); + fcol[GRN] = f * (rgbe[GRN] + 0.5f); + fcol[BLU] = f * (rgbe[BLU] + 0.5f); + } } /* float color -> rgbe */ static void FLOAT2RGBE(fCOLOR fcol, RGBE rgbe) { - int e; - float d = (fcol[RED] > fcol[GRN]) ? fcol[RED] : fcol[GRN]; - if (fcol[BLU] > d) d = fcol[BLU]; - if (d <= 1e-32f) - rgbe[RED] = rgbe[GRN] = rgbe[BLU] = rgbe[EXP] = 0; - else { - d = (float)frexp(d, &e) * 256.0f / d; - rgbe[RED] = (unsigned char)(fcol[RED] * d); - rgbe[GRN] = (unsigned char)(fcol[GRN] * d); - rgbe[BLU] = (unsigned char)(fcol[BLU] * d); - rgbe[EXP] = (unsigned char)(e + COLXS); - } + int e; + float d = (fcol[RED] > fcol[GRN]) ? fcol[RED] : fcol[GRN]; + if (fcol[BLU] > d) + d = fcol[BLU]; + if (d <= 1e-32f) + rgbe[RED] = rgbe[GRN] = rgbe[BLU] = rgbe[EXP] = 0; + else { + d = (float)frexp(d, &e) * 256.0f / d; + rgbe[RED] = (unsigned char)(fcol[RED] * d); + rgbe[GRN] = (unsigned char)(fcol[GRN] * d); + rgbe[BLU] = (unsigned char)(fcol[BLU] * d); + rgbe[EXP] = (unsigned char)(e + COLXS); + } } /* ImBuf read */ int imb_is_a_hdr(const unsigned char *buf) { - /* For recognition, Blender only loads first 32 bytes, so use #?RADIANCE id instead */ - /* update: actually, the 'RADIANCE' part is just an optional program name, the magic word is really only the '#?' part */ - //if (strstr((char *)buf, "#?RADIANCE")) return 1; - if (strstr((char *)buf, "#?")) return 1; - // if (strstr((char *)buf, "32-bit_rle_rgbe")) return 1; - return 0; + /* For recognition, Blender only loads first 32 bytes, so use #?RADIANCE id instead */ + /* update: actually, the 'RADIANCE' part is just an optional program name, the magic word is really only the '#?' part */ + //if (strstr((char *)buf, "#?RADIANCE")) return 1; + if (strstr((char *)buf, "#?")) + return 1; + // if (strstr((char *)buf, "32-bit_rle_rgbe")) return 1; + return 0; } -struct ImBuf *imb_loadhdr(const unsigned char *mem, size_t size, int flags, char colorspace[IM_MAX_SPACE]) +struct ImBuf *imb_loadhdr(const unsigned char *mem, + size_t size, + int flags, + char colorspace[IM_MAX_SPACE]) { - struct ImBuf *ibuf; - RGBE *sline; - fCOLOR fcol; - float *rect_float; - int found = 0; - int width = 0, height = 0; - const unsigned char *ptr, *mem_eof = mem + size; - char oriY[80], oriX[80]; - - if (imb_is_a_hdr((void *)mem)) { - colorspace_set_default_role(colorspace, IM_MAX_SPACE, COLOR_ROLE_DEFAULT_FLOAT); - - /* find empty line, next line is resolution info */ - size_t x; - for (x = 1; x < size; x++) { - if ((mem[x - 1] == '\n') && (mem[x] == '\n')) { - found = 1; - break; - } - } - if (found && (x < (size + 2))) { - if (sscanf((char *)&mem[x + 1], "%79s %d %79s %d", (char *)&oriY, &height, - (char *)&oriX, &width) != 4) - { - return NULL; - } - - /* find end of this line, data right behind it */ - ptr = (unsigned char *)strchr((char *)&mem[x + 1], '\n'); - ptr++; - - if (flags & IB_test) ibuf = IMB_allocImBuf(width, height, 32, 0); - else ibuf = IMB_allocImBuf(width, height, 32, (flags & IB_rect) | IB_rectfloat); - - if (UNLIKELY(ibuf == NULL)) { - return NULL; - } - ibuf->ftype = IMB_FTYPE_RADHDR; - - if (flags & IB_alphamode_detect) - ibuf->flags |= IB_alphamode_premul; - - if (flags & IB_test) { - return ibuf; - } - - /* read in and decode the actual data */ - sline = (RGBE *)MEM_mallocN(sizeof(*sline) * width, __func__); - rect_float = ibuf->rect_float; - - for (size_t y = 0; y < height; y++) { - ptr = freadcolrs(sline, ptr, width, mem_eof); - if (ptr == NULL) { - printf("WARNING! HDR decode error, image may be just truncated, or completely wrong...\n"); - break; - } - for (x = 0; x < width; x++) { - /* convert to ldr */ - RGBE2FLOAT(sline[x], fcol); - *rect_float++ = fcol[RED]; - *rect_float++ = fcol[GRN]; - *rect_float++ = fcol[BLU]; - *rect_float++ = 1.0f; - } - } - MEM_freeN(sline); - if (oriY[0] == '-') IMB_flipy(ibuf); - - if (flags & IB_rect) { - IMB_rect_from_float(ibuf); - } - - return ibuf; - } - //else printf("Data not found!\n"); - } - //else printf("Not a valid radiance HDR file!\n"); - - return NULL; + struct ImBuf *ibuf; + RGBE *sline; + fCOLOR fcol; + float *rect_float; + int found = 0; + int width = 0, height = 0; + const unsigned char *ptr, *mem_eof = mem + size; + char oriY[80], oriX[80]; + + if (imb_is_a_hdr((void *)mem)) { + colorspace_set_default_role(colorspace, IM_MAX_SPACE, COLOR_ROLE_DEFAULT_FLOAT); + + /* find empty line, next line is resolution info */ + size_t x; + for (x = 1; x < size; x++) { + if ((mem[x - 1] == '\n') && (mem[x] == '\n')) { + found = 1; + break; + } + } + if (found && (x < (size + 2))) { + if (sscanf((char *)&mem[x + 1], + "%79s %d %79s %d", + (char *)&oriY, + &height, + (char *)&oriX, + &width) != 4) { + return NULL; + } + + /* find end of this line, data right behind it */ + ptr = (unsigned char *)strchr((char *)&mem[x + 1], '\n'); + ptr++; + + if (flags & IB_test) + ibuf = IMB_allocImBuf(width, height, 32, 0); + else + ibuf = IMB_allocImBuf(width, height, 32, (flags & IB_rect) | IB_rectfloat); + + if (UNLIKELY(ibuf == NULL)) { + return NULL; + } + ibuf->ftype = IMB_FTYPE_RADHDR; + + if (flags & IB_alphamode_detect) + ibuf->flags |= IB_alphamode_premul; + + if (flags & IB_test) { + return ibuf; + } + + /* read in and decode the actual data */ + sline = (RGBE *)MEM_mallocN(sizeof(*sline) * width, __func__); + rect_float = ibuf->rect_float; + + for (size_t y = 0; y < height; y++) { + ptr = freadcolrs(sline, ptr, width, mem_eof); + if (ptr == NULL) { + printf( + "WARNING! HDR decode error, image may be just truncated, or completely wrong...\n"); + break; + } + for (x = 0; x < width; x++) { + /* convert to ldr */ + RGBE2FLOAT(sline[x], fcol); + *rect_float++ = fcol[RED]; + *rect_float++ = fcol[GRN]; + *rect_float++ = fcol[BLU]; + *rect_float++ = 1.0f; + } + } + MEM_freeN(sline); + if (oriY[0] == '-') + IMB_flipy(ibuf); + + if (flags & IB_rect) { + IMB_rect_from_float(ibuf); + } + + return ibuf; + } + //else printf("Data not found!\n"); + } + //else printf("Not a valid radiance HDR file!\n"); + + return NULL; } /* ImBuf write */ static int fwritecolrs(FILE *file, int width, int channels, unsigned char *ibufscan, float *fpscan) { - int beg, c2, cnt = 0; - fCOLOR fcol; - RGBE rgbe, *rgbe_scan; - - if (UNLIKELY((ibufscan == NULL) && (fpscan == NULL))) { - return 0; - } - - rgbe_scan = (RGBE *)MEM_mallocN(sizeof(RGBE) * width, "radhdr_write_tmpscan"); - - /* convert scanline */ - for (size_t i = 0, j = 0; i < width; i++) { - if (fpscan) { - fcol[RED] = fpscan[j]; - fcol[GRN] = (channels >= 2) ? fpscan[j + 1] : fpscan[j]; - fcol[BLU] = (channels >= 3) ? fpscan[j + 2] : fpscan[j]; - } - else { - fcol[RED] = (float)ibufscan[j] / 255.f; - fcol[GRN] = (float)((channels >= 2) ? ibufscan[j + 1] : ibufscan[j]) / 255.f; - fcol[BLU] = (float)((channels >= 3) ? ibufscan[j + 2] : ibufscan[j]) / 255.f; - } - FLOAT2RGBE(fcol, rgbe); - COPY_RGBE(rgbe, rgbe_scan[i]); - j += channels; - } - - if ((width < MINELEN) | (width > MAXELEN)) { /* OOBs, write out flat */ - int x = fwrite((char *)rgbe_scan, sizeof(RGBE), width, file) - width; - MEM_freeN(rgbe_scan); - return x; - } - /* put magic header */ - putc(2, file); - putc(2, file); - putc((unsigned char)(width >> 8), file); - putc((unsigned char)(width & 255), file); - /* put components separately */ - for (size_t i = 0; i < 4; i++) { - for (size_t j = 0; j < width; j += cnt) { /* find next run */ - for (beg = j; beg < width; beg += cnt) { - for (cnt = 1; (cnt < 127) && ((beg + cnt) < width) && (rgbe_scan[beg + cnt][i] == rgbe_scan[beg][i]); cnt++) ; - if (cnt >= MINRUN) break; /* long enough */ - } - if (((beg - j) > 1) && ((beg - j) < MINRUN)) { - c2 = j + 1; - while (rgbe_scan[c2++][i] == rgbe_scan[j][i]) { - if (c2 == beg) { /* short run */ - putc((unsigned char)(128 + beg - j), file); - putc((unsigned char)(rgbe_scan[j][i]), file); - j = beg; - break; - } - } - } - while (j < beg) { /* write out non-run */ - if ((c2 = beg - j) > 128) c2 = 128; - putc((unsigned char)(c2), file); - while (c2--) putc(rgbe_scan[j++][i], file); - } - if (cnt >= MINRUN) { /* write out run */ - putc((unsigned char)(128 + cnt), file); - putc(rgbe_scan[beg][i], file); - } - else { - cnt = 0; - } - } - } - MEM_freeN(rgbe_scan); - return(ferror(file) ? -1 : 0); + int beg, c2, cnt = 0; + fCOLOR fcol; + RGBE rgbe, *rgbe_scan; + + if (UNLIKELY((ibufscan == NULL) && (fpscan == NULL))) { + return 0; + } + + rgbe_scan = (RGBE *)MEM_mallocN(sizeof(RGBE) * width, "radhdr_write_tmpscan"); + + /* convert scanline */ + for (size_t i = 0, j = 0; i < width; i++) { + if (fpscan) { + fcol[RED] = fpscan[j]; + fcol[GRN] = (channels >= 2) ? fpscan[j + 1] : fpscan[j]; + fcol[BLU] = (channels >= 3) ? fpscan[j + 2] : fpscan[j]; + } + else { + fcol[RED] = (float)ibufscan[j] / 255.f; + fcol[GRN] = (float)((channels >= 2) ? ibufscan[j + 1] : ibufscan[j]) / 255.f; + fcol[BLU] = (float)((channels >= 3) ? ibufscan[j + 2] : ibufscan[j]) / 255.f; + } + FLOAT2RGBE(fcol, rgbe); + COPY_RGBE(rgbe, rgbe_scan[i]); + j += channels; + } + + if ((width < MINELEN) | (width > MAXELEN)) { /* OOBs, write out flat */ + int x = fwrite((char *)rgbe_scan, sizeof(RGBE), width, file) - width; + MEM_freeN(rgbe_scan); + return x; + } + /* put magic header */ + putc(2, file); + putc(2, file); + putc((unsigned char)(width >> 8), file); + putc((unsigned char)(width & 255), file); + /* put components separately */ + for (size_t i = 0; i < 4; i++) { + for (size_t j = 0; j < width; j += cnt) { /* find next run */ + for (beg = j; beg < width; beg += cnt) { + for (cnt = 1; (cnt < 127) && ((beg + cnt) < width) && + (rgbe_scan[beg + cnt][i] == rgbe_scan[beg][i]); + cnt++) + ; + if (cnt >= MINRUN) + break; /* long enough */ + } + if (((beg - j) > 1) && ((beg - j) < MINRUN)) { + c2 = j + 1; + while (rgbe_scan[c2++][i] == rgbe_scan[j][i]) { + if (c2 == beg) { /* short run */ + putc((unsigned char)(128 + beg - j), file); + putc((unsigned char)(rgbe_scan[j][i]), file); + j = beg; + break; + } + } + } + while (j < beg) { /* write out non-run */ + if ((c2 = beg - j) > 128) + c2 = 128; + putc((unsigned char)(c2), file); + while (c2--) + putc(rgbe_scan[j++][i], file); + } + if (cnt >= MINRUN) { /* write out run */ + putc((unsigned char)(128 + cnt), file); + putc(rgbe_scan[beg][i], file); + } + else { + cnt = 0; + } + } + } + MEM_freeN(rgbe_scan); + return (ferror(file) ? -1 : 0); } static void writeHeader(FILE *file, int width, int height) { - fprintf(file, "#?RADIANCE"); - fputc(10, file); - fprintf(file, "# %s", "Created with Blender"); - fputc(10, file); - fprintf(file, "EXPOSURE=%25.13f", 1.0); - fputc(10, file); - fprintf(file, "FORMAT=32-bit_rle_rgbe"); - fputc(10, file); - fputc(10, file); - fprintf(file, "-Y %d +X %d", height, width); - fputc(10, file); + fprintf(file, "#?RADIANCE"); + fputc(10, file); + fprintf(file, "# %s", "Created with Blender"); + fputc(10, file); + fprintf(file, "EXPOSURE=%25.13f", 1.0); + fputc(10, file); + fprintf(file, "FORMAT=32-bit_rle_rgbe"); + fputc(10, file); + fputc(10, file); + fprintf(file, "-Y %d +X %d", height, width); + fputc(10, file); } int imb_savehdr(struct ImBuf *ibuf, const char *name, int flags) { - FILE *file = BLI_fopen(name, "wb"); - float *fp = NULL; - size_t width = ibuf->x, height = ibuf->y; - unsigned char *cp = NULL; - - (void)flags; /* unused */ - - if (file == NULL) { - return 0; - } - - writeHeader(file, width, height); - - if (ibuf->rect) - cp = (unsigned char *)ibuf->rect + ibuf->channels * (height - 1) * width; - if (ibuf->rect_float) - fp = ibuf->rect_float + ibuf->channels * (height - 1) * width; - - for (size_t y = 0; y < height; y++) { - if (fwritecolrs(file, width, ibuf->channels, cp, fp) < 0) { - fclose(file); - printf("HDR write error\n"); - return 0; - } - if (cp) cp -= ibuf->channels * width; - if (fp) fp -= ibuf->channels * width; - } - - fclose(file); - return 1; + FILE *file = BLI_fopen(name, "wb"); + float *fp = NULL; + size_t width = ibuf->x, height = ibuf->y; + unsigned char *cp = NULL; + + (void)flags; /* unused */ + + if (file == NULL) { + return 0; + } + + writeHeader(file, width, height); + + if (ibuf->rect) + cp = (unsigned char *)ibuf->rect + ibuf->channels * (height - 1) * width; + if (ibuf->rect_float) + fp = ibuf->rect_float + ibuf->channels * (height - 1) * width; + + for (size_t y = 0; y < height; y++) { + if (fwritecolrs(file, width, ibuf->channels, cp, fp) < 0) { + fclose(file); + printf("HDR write error\n"); + return 0; + } + if (cp) + cp -= ibuf->channels * width; + if (fp) + fp -= ibuf->channels * width; + } + + fclose(file); + return 1; } |