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