|
Blender
V2.59
|
00001 /* 00002 * radiance_hdr.c 00003 * 00004 * $Id: radiance_hdr.c 35239 2011-02-27 20:23:21Z jesterking $ 00005 * 00006 * ***** BEGIN GPL LICENSE BLOCK ***** 00007 * 00008 * This program is free software; you can redistribute it and/or 00009 * modify it under the terms of the GNU General Public License 00010 * as published by the Free Software Foundation; either version 2 00011 * of the License, or (at your option) any later version. 00012 * 00013 * This program is distributed in the hope that it will be useful, 00014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00016 * GNU General Public License for more details. 00017 * 00018 * You should have received a copy of the GNU General Public License 00019 * along with this program; if not, write to the Free Software Foundation, 00020 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00021 * 00022 * The Original Code is Copyright 00023 * All rights reserved. 00024 * 00025 * The Original Code is: all of this file. 00026 * 00027 * Contributor(s): none yet. 00028 * 00029 * ***** END GPL LICENSE BLOCK ***** 00030 */ 00031 00037 #ifdef WITH_HDR 00038 00039 /* ---------------------------------------------------------------------- 00040 Radiance High Dynamic Range image file IO 00041 For description and code for reading/writing of radiance hdr files 00042 by Greg Ward, refer to: 00043 http://radsite.lbl.gov/radiance/refer/Notes/picture_format.html 00044 ---------------------------------------------------------------------- 00045 */ 00046 00047 #ifdef WIN32 00048 #include <io.h> 00049 #endif 00050 00051 #include "MEM_guardedalloc.h" 00052 00053 #include "BLI_blenlib.h" 00054 00055 #include "imbuf.h" 00056 00057 #include "IMB_imbuf_types.h" 00058 #include "IMB_imbuf.h" 00059 00060 #include "IMB_allocimbuf.h" 00061 #include "IMB_filetype.h" 00062 00063 /* needed constants */ 00064 #define MINELEN 8 00065 #define MAXELEN 0x7fff 00066 #define MINRUN 4 /* minimum run length */ 00067 #define RED 0 00068 #define GRN 1 00069 #define BLU 2 00070 #define EXP 3 00071 #define COLXS 128 00072 #define STR_MAX 540 00073 typedef unsigned char RGBE[4]; 00074 typedef float fCOLOR[3]; 00075 /* copy source -> dest */ 00076 #define copy_rgbe(c1, c2) (c2[RED]=c1[RED], c2[GRN]=c1[GRN], c2[BLU]=c1[BLU], c2[EXP]=c1[EXP]) 00077 #define copy_fcol(f1, f2) (f2[RED]=f1[RED], f2[GRN]=f1[GRN], f2[BLU]=f1[BLU]) 00078 00079 /* read routines */ 00080 static unsigned char* oldreadcolrs(RGBE *scan, unsigned char *mem, int xmax) 00081 { 00082 int i, rshift = 0, len = xmax; 00083 while (len > 0) { 00084 scan[0][RED] = *mem++; 00085 scan[0][GRN] = *mem++; 00086 scan[0][BLU] = *mem++; 00087 scan[0][EXP] = *mem++; 00088 if (scan[0][RED] == 1 && scan[0][GRN] == 1 && scan[0][BLU] == 1) { 00089 for (i=scan[0][EXP]<<rshift;i>0;i--) { 00090 copy_rgbe(scan[-1], scan[0]); 00091 scan++; 00092 len--; 00093 } 00094 rshift += 8; 00095 } 00096 else { 00097 scan++; 00098 len--; 00099 rshift = 0; 00100 } 00101 } 00102 return mem; 00103 } 00104 00105 static unsigned char* freadcolrs(RGBE *scan, unsigned char* mem, int xmax) 00106 { 00107 int i, j, code, val; 00108 00109 if ((xmax < MINELEN) | (xmax > MAXELEN)) return oldreadcolrs(scan, mem, xmax); 00110 00111 i = *mem++; 00112 if (i != 2) return oldreadcolrs(scan, mem-1, xmax); 00113 00114 scan[0][GRN] = *mem++; 00115 scan[0][BLU] = *mem++; 00116 00117 i = *mem++; 00118 if (((scan[0][BLU] << 8) | i) != xmax) return NULL; 00119 00120 for (i=0;i<4;i++) 00121 for (j=0;j<xmax;) { 00122 code = *mem++; 00123 if (code > 128) { 00124 code &= 127; 00125 val = *mem++; 00126 while (code--) 00127 scan[j++][i] = (unsigned char)val; 00128 } 00129 else 00130 while (code--) 00131 scan[j++][i] = *mem++; 00132 } 00133 return mem; 00134 } 00135 00136 /* helper functions */ 00137 00138 /* rgbe -> float color */ 00139 static void RGBE2FLOAT(RGBE rgbe, fCOLOR fcol) 00140 { 00141 if (rgbe[EXP]==0) { 00142 fcol[RED] = fcol[GRN] = fcol[BLU] = 0; 00143 } 00144 else { 00145 float f = ldexp(1.0, rgbe[EXP]-(COLXS+8)); 00146 fcol[RED] = f*(rgbe[RED] + 0.5f); 00147 fcol[GRN] = f*(rgbe[GRN] + 0.5f); 00148 fcol[BLU] = f*(rgbe[BLU] + 0.5f); 00149 } 00150 } 00151 00152 /* float color -> rgbe */ 00153 static void FLOAT2RGBE(fCOLOR fcol, RGBE rgbe) 00154 { 00155 int e; 00156 float d = (fcol[RED]>fcol[GRN]) ? fcol[RED] : fcol[GRN]; 00157 if (fcol[BLU]>d) d = fcol[BLU]; 00158 if (d <= 1e-32f) 00159 rgbe[RED] = rgbe[GRN] = rgbe[BLU] = rgbe[EXP] = 0; 00160 else { 00161 d = frexp(d, &e) * 256.f / d; 00162 rgbe[RED] = (unsigned char)(fcol[RED] * d); 00163 rgbe[GRN] = (unsigned char)(fcol[GRN] * d); 00164 rgbe[BLU] = (unsigned char)(fcol[BLU] * d); 00165 rgbe[EXP] = (unsigned char)(e + COLXS); 00166 } 00167 } 00168 00169 /* ImBuf read */ 00170 00171 int imb_is_a_hdr(unsigned char *buf) 00172 { 00173 // For recognition, Blender only loads first 32 bytes, so use #?RADIANCE id instead 00174 // update: actually, the 'RADIANCE' part is just an optional program name, the magic word is really only the '#?' part 00175 //if (strstr((char*)buf, "#?RADIANCE")) return 1; 00176 if (strstr((char*)buf, "#?")) return 1; 00177 // if (strstr((char*)buf, "32-bit_rle_rgbe")) return 1; 00178 return 0; 00179 } 00180 00181 struct ImBuf *imb_loadhdr(unsigned char *mem, size_t size, int flags) 00182 { 00183 struct ImBuf* ibuf; 00184 RGBE* sline; 00185 fCOLOR fcol; 00186 float* rect_float; 00187 int found=0; 00188 int width=0, height=0; 00189 int x, y; 00190 unsigned char* ptr; 00191 char oriY[80], oriX[80]; 00192 00193 if (imb_is_a_hdr((void*)mem)) 00194 { 00195 /* find empty line, next line is resolution info */ 00196 for (x=1;x<size;x++) { 00197 if ((mem[x-1]=='\n') && (mem[x]=='\n')) { 00198 found = 1; 00199 break; 00200 } 00201 } 00202 if (found && (x<(size + 2))) { 00203 if (sscanf((char *)&mem[x+1], "%79s %d %79s %d", (char*)&oriY, &height, 00204 (char*)&oriX, &width) != 4) return NULL; 00205 00206 /* find end of this line, data right behind it */ 00207 ptr = (unsigned char *)strchr((char*)&mem[x+1], '\n'); 00208 ptr++; 00209 00210 if (flags & IB_test) ibuf = IMB_allocImBuf(width, height, 32, 0); 00211 else ibuf = IMB_allocImBuf(width, height, 32, (flags & IB_rect)|IB_rectfloat); 00212 00213 if (ibuf==NULL) return NULL; 00214 ibuf->ftype = RADHDR; 00215 ibuf->profile = IB_PROFILE_LINEAR_RGB; 00216 00217 if (flags & IB_test) return ibuf; 00218 00219 /* read in and decode the actual data */ 00220 sline = (RGBE*)MEM_mallocN(sizeof(RGBE)*width, "radhdr_read_tmpscan"); 00221 rect_float = (float *)ibuf->rect_float; 00222 00223 for (y=0;y<height;y++) { 00224 ptr = freadcolrs(sline, ptr, width); 00225 if (ptr==NULL) { 00226 printf("HDR decode error\n"); 00227 MEM_freeN(sline); 00228 return ibuf; 00229 } 00230 for (x=0;x<width;x++) { 00231 /* convert to ldr */ 00232 RGBE2FLOAT(sline[x], fcol); 00233 *rect_float++ = fcol[RED]; 00234 *rect_float++ = fcol[GRN]; 00235 *rect_float++ = fcol[BLU]; 00236 *rect_float++ = 1.0f; 00237 } 00238 } 00239 MEM_freeN(sline); 00240 if (oriY[0]=='-') IMB_flipy(ibuf); 00241 00242 if (flags & IB_rect) { 00243 IMB_rect_from_float(ibuf); 00244 } 00245 00246 return ibuf; 00247 } 00248 //else printf("Data not found!\n"); 00249 } 00250 //else printf("Not a valid radiance HDR file!\n"); 00251 00252 return NULL; 00253 } 00254 00255 /* ImBuf write */ 00256 static int fwritecolrs(FILE* file, int width, int channels, unsigned char* ibufscan, float* fpscan) 00257 { 00258 int x, i, j, beg, c2, cnt=0; 00259 fCOLOR fcol; 00260 RGBE rgbe, *rgbe_scan; 00261 00262 if ((ibufscan==NULL) && (fpscan==NULL)) return 0; 00263 00264 rgbe_scan = (RGBE*)MEM_mallocN(sizeof(RGBE)*width, "radhdr_write_tmpscan"); 00265 00266 /* convert scanline */ 00267 j= 0; 00268 for (i=0;i<width;i++) { 00269 if (fpscan) { 00270 fcol[RED] = fpscan[j]; 00271 fcol[GRN] = (channels >= 2)? fpscan[j+1]: fpscan[j]; 00272 fcol[BLU] = (channels >= 3)? fpscan[j+2]: fpscan[j]; 00273 } else { 00274 fcol[RED] = (float)ibufscan[j] / 255.f; 00275 fcol[GRN] = (float)((channels >= 2)? ibufscan[j+1]: ibufscan[j]) / 255.f; 00276 fcol[BLU] = (float)((channels >= 3)? ibufscan[j+2]: ibufscan[j]) / 255.f; 00277 } 00278 FLOAT2RGBE(fcol, rgbe); 00279 copy_rgbe(rgbe, rgbe_scan[i]); 00280 j+=channels; 00281 } 00282 00283 if ((width < MINELEN) | (width > MAXELEN)) { /* OOBs, write out flat */ 00284 x=fwrite((char *)rgbe_scan, sizeof(RGBE), width, file) - width; 00285 MEM_freeN(rgbe_scan); 00286 return x; 00287 } 00288 /* put magic header */ 00289 putc(2, file); 00290 putc(2, file); 00291 putc((unsigned char)(width >> 8), file); 00292 putc((unsigned char)(width & 255), file); 00293 /* put components separately */ 00294 for (i=0;i<4;i++) { 00295 for (j=0;j<width;j+=cnt) { /* find next run */ 00296 for (beg=j;beg<width;beg+=cnt) { 00297 for (cnt=1;(cnt<127) && ((beg+cnt)<width) && (rgbe_scan[beg+cnt][i] == rgbe_scan[beg][i]); cnt++); 00298 if (cnt>=MINRUN) break; /* long enough */ 00299 } 00300 if (((beg-j)>1) && ((beg-j) < MINRUN)) { 00301 c2 = j+1; 00302 while (rgbe_scan[c2++][i] == rgbe_scan[j][i]) 00303 if (c2 == beg) { /* short run */ 00304 putc((unsigned char)(128+beg-j), file); 00305 putc((unsigned char)(rgbe_scan[j][i]), file); 00306 j = beg; 00307 break; 00308 } 00309 } 00310 while (j < beg) { /* write out non-run */ 00311 if ((c2 = beg-j) > 128) c2 = 128; 00312 putc((unsigned char)(c2), file); 00313 while (c2--) putc(rgbe_scan[j++][i], file); 00314 } 00315 if (cnt >= MINRUN) { /* write out run */ 00316 putc((unsigned char)(128+cnt), file); 00317 putc(rgbe_scan[beg][i], file); 00318 } 00319 else cnt = 0; 00320 } 00321 } 00322 MEM_freeN(rgbe_scan); 00323 return(ferror(file) ? -1 : 0); 00324 } 00325 00326 static void writeHeader(FILE *file, int width, int height) 00327 { 00328 fprintf(file, "#?RADIANCE"); 00329 fputc(10, file); 00330 fprintf(file, "# %s", "Created with Blender"); 00331 fputc(10, file); 00332 fprintf(file, "EXPOSURE=%25.13f", 1.0); 00333 fputc(10, file); 00334 fprintf(file, "FORMAT=32-bit_rle_rgbe"); 00335 fputc(10, file); 00336 fputc(10, file); 00337 fprintf(file, "-Y %d +X %d", height, width); 00338 fputc(10, file); 00339 } 00340 00341 int imb_savehdr(struct ImBuf *ibuf, const char *name, int flags) 00342 { 00343 FILE* file = fopen(name, "wb"); 00344 float *fp= NULL; 00345 int y, width=ibuf->x, height=ibuf->y; 00346 unsigned char *cp= NULL; 00347 00348 (void)flags; /* unused */ 00349 00350 if (file==NULL) return 0; 00351 00352 writeHeader(file, width, height); 00353 00354 if(ibuf->rect) 00355 cp= (unsigned char *)ibuf->rect + ibuf->channels*(height-1)*width; 00356 if(ibuf->rect_float) 00357 fp= ibuf->rect_float + ibuf->channels*(height-1)*width; 00358 00359 for (y=height-1;y>=0;y--) { 00360 if (fwritecolrs(file, width, ibuf->channels, cp, fp) < 0) { 00361 fclose(file); 00362 printf("HDR write error\n"); 00363 return 0; 00364 } 00365 if(cp) cp-= ibuf->channels*width; 00366 if(fp) fp-= ibuf->channels*width; 00367 } 00368 00369 fclose(file); 00370 return 1; 00371 } 00372 00373 #endif /* WITH_HDR */