1 /* Read Radiance (.hdr) files
2 *
3 * 3/3/09
4 * - write packed data, a separate im_rad2float() operation can unpack
5 * 23/3/09
6 * - add radiance write
7 * 20/12/11
8 * - reworked as some fns ready for new-style classes
9 * 13/12/12
10 * - tag RGB rad images as scRGB
11 * 4/11/13
12 * - support sequential read
13 * 5/11/13
14 * - rewritten scanline encode and decode, now much faster
15 * 23/1/14
16 * - put the reader globals into a struct so we can have many active
17 * readers
18 * 23/5/16
19 * - add buffer save functions
20 * 28/2/17
21 * - use dbuf for buffer output
22 * 4/4/17
23 * - reduce stack use to help musl
24 * 22/7/18
25 * - update code from radiance ... pasted in from rad5R1
26 * - expand fs[] buffer to prevent out of bounds write [HongxuChen]
27 * 23/7/18
28 * - fix a buffer overflow for incorrectly coded old-style RLE
29 * [HongxuChen]
30 * 6/11/19
31 * - revise for VipsConnection
32 */
33
34 /*
35
36 This file is part of VIPS.
37
38 VIPS is free software; you can redistribute it and/or modify
39 it under the terms of the GNU Lesser General Public License as published by
40 the Free Software Foundation; either version 2 of the License, or
41 (at your option) any later version.
42
43 This program is distributed in the hope that it will be useful,
44 but WITHOUT ANY WARRANTY; without even the implied warranty of
45 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
46 GNU Lesser General Public License for more details.
47
48 You should have received a copy of the GNU Lesser General Public License
49 along with this program; if not, write to the Free Software
50 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
51 02110-1301 USA
52
53 */
54
55 /*
56
57 These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
58
59 */
60
61 /*
62
63 Remaining issues:
64
65 + it ignores some header fields, like VIEW and DATE
66
67 + it will not rotate/flip as the FORMAT string asks
68
69 */
70
71 /*
72
73 Sections of this reader from Greg Ward and Radiance with kind
74 permission. The Radience copyright notice appears below.
75
76 */
77
78 /* ====================================================================
79 * The Radiance Software License, Version 1.0
80 *
81 * Copyright (c) 1990 - 2009 The Regents of the University of California,
82 * through Lawrence Berkeley National Laboratory. All rights reserved.
83 *
84 * Redistribution and use in source and binary forms, with or without
85 * modification, are permitted provided that the following conditions
86 * are met:
87 *
88 * 1. Redistributions of source code must retain the above copyright
89 * notice, this list of conditions and the following disclaimer.
90 *
91 * 2. Redistributions in binary form must reproduce the above copyright
92 * notice, this list of conditions and the following disclaimer in
93 * the documentation and/or other materials provided with the
94 * distribution.
95 *
96 * 3. The end-user documentation included with the redistribution,
97 * if any, must include the following acknowledgment:
98 * "This product includes Radiance software
99 * (http://radsite.lbl.gov/)
100 * developed by the Lawrence Berkeley National Laboratory
101 * (http://www.lbl.gov/)."
102 * Alternately, this acknowledgment may appear in the software itself,
103 * if and wherever such third-party acknowledgments normally appear.
104 *
105 * 4. The names "Radiance," "Lawrence Berkeley National Laboratory"
106 * and "The Regents of the University of California" must
107 * not be used to endorse or promote products derived from this
108 * software without prior written permission. For written
109 * permission, please contact radiance@radsite.lbl.gov.
110 *
111 * 5. Products derived from this software may not be called "Radiance",
112 * nor may "Radiance" appear in their name, without prior written
113 * permission of Lawrence Berkeley National Laboratory.
114 *
115 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
116 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
117 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
118 * DISCLAIMED. IN NO EVENT SHALL Lawrence Berkeley National Laboratory OR
119 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
120 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
121 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
122 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
123 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
124 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
125 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
126 * SUCH DAMAGE.
127 * ====================================================================
128 *
129 * This software consists of voluntary contributions made by many
130 * individuals on behalf of Lawrence Berkeley National Laboratory. For more
131 * information on Lawrence Berkeley National Laboratory, please see
132 * <http://www.lbl.gov/>.
133 */
134
135 /*
136 #define DEBUG
137 */
138
139 #ifdef HAVE_CONFIG_H
140 #include <config.h>
141 #endif /*HAVE_CONFIG_H*/
142 #include <vips/intl.h>
143
144 #ifdef HAVE_RADIANCE
145
146 #include <stdio.h>
147 #include <assert.h>
148 #include <stdlib.h>
149 #include <stdarg.h>
150 #include <string.h>
151 #include <ctype.h>
152 #include <math.h>
153
154 #include <vips/vips.h>
155 #include <vips/internal.h>
156 #include <vips/debug.h>
157
158 #include "pforeign.h"
159
160 /* Begin copy-paste from Radiance sources.
161 *
162 * To update:
163 *
164 * 1. Download and unpack latest stable radiance
165 * 2. ray/src/common has the files we need ... copy in this order:
166 * colour.h
167 * resolu.h
168 * rtio.h
169 * fputword.c
170 * colour.c
171 * resolu.c
172 * header.c
173 * 3. trim each one down, removing extern decls
174 * 4. make all functions static
175 * 5. reorder to remove forward refs
176 * 6. remove unused funcs, mostly related to HDR write
177 */
178
179 #define RED 0
180 #define GRN 1
181 #define BLU 2
182 #define CIEX 0 /* or, if input is XYZ... */
183 #define CIEY 1
184 #define CIEZ 2
185 #define EXP 3 /* exponent same for either format */
186 #define COLXS 128 /* excess used for exponent */
187 #define WHT 3 /* used for RGBPRIMS type */
188
189 #undef uby8
190 #define uby8 unsigned char /* 8-bit unsigned integer */
191
192 typedef uby8 COLR[4]; /* red, green, blue (or X,Y,Z), exponent */
193
194 typedef float COLORV;
195 typedef COLORV COLOR[3]; /* red, green, blue (or X,Y,Z) */
196
197 typedef float RGBPRIMS[4][2]; /* (x,y) chromaticities for RGBW */
198 typedef float (*RGBPRIMP)[2]; /* pointer to RGBPRIMS array */
199
200 typedef float COLORMAT[3][3]; /* color coordinate conversion matrix */
201
202 #define copycolr(c1,c2) (c1[0]=c2[0],c1[1]=c2[1], \
203 c1[2]=c2[2],c1[3]=c2[3])
204
205 #define colval(col,pri) ((col)[pri])
206
207 #define setcolor(col,r,g,b) ((col)[RED]=(r),(col)[GRN]=(g),(col)[BLU]=(b))
208
209 #define copycolor(c1,c2) ((c1)[0]=(c2)[0],(c1)[1]=(c2)[1],(c1)[2]=(c2)[2])
210
211 #define scalecolor(col,sf) ((col)[0]*=(sf),(col)[1]*=(sf),(col)[2]*=(sf))
212
213 #define addcolor(c1,c2) ((c1)[0]+=(c2)[0],(c1)[1]+=(c2)[1],(c1)[2]+=(c2)[2])
214
215 #define multcolor(c1,c2) ((c1)[0]*=(c2)[0],(c1)[1]*=(c2)[1],(c1)[2]*=(c2)[2])
216
217 #ifdef NTSC
218 #define CIE_x_r 0.670 /* standard NTSC primaries */
219 #define CIE_y_r 0.330
220 #define CIE_x_g 0.210
221 #define CIE_y_g 0.710
222 #define CIE_x_b 0.140
223 #define CIE_y_b 0.080
224 #define CIE_x_w (1./3.) /* use true white */
225 #define CIE_y_w (1./3.)
226 #else
227 #define CIE_x_r 0.640 /* nominal CRT primaries */
228 #define CIE_y_r 0.330
229 #define CIE_x_g 0.290
230 #define CIE_y_g 0.600
231 #define CIE_x_b 0.150
232 #define CIE_y_b 0.060
233 #define CIE_x_w (1./3.) /* use true white */
234 #define CIE_y_w (1./3.)
235 #endif
236
237 #define STDPRIMS {{CIE_x_r,CIE_y_r},{CIE_x_g,CIE_y_g}, \
238 {CIE_x_b,CIE_y_b},{CIE_x_w,CIE_y_w}}
239
240 #define CIE_D ( CIE_x_r*(CIE_y_g - CIE_y_b) + \
241 CIE_x_g*(CIE_y_b - CIE_y_r) + \
242 CIE_x_b*(CIE_y_r - CIE_y_g) )
243 #define CIE_C_rD ( (1./CIE_y_w) * \
244 ( CIE_x_w*(CIE_y_g - CIE_y_b) - \
245 CIE_y_w*(CIE_x_g - CIE_x_b) + \
246 CIE_x_g*CIE_y_b - CIE_x_b*CIE_y_g ) )
247 #define CIE_C_gD ( (1./CIE_y_w) * \
248 ( CIE_x_w*(CIE_y_b - CIE_y_r) - \
249 CIE_y_w*(CIE_x_b - CIE_x_r) - \
250 CIE_x_r*CIE_y_b + CIE_x_b*CIE_y_r ) )
251 #define CIE_C_bD ( (1./CIE_y_w) * \
252 ( CIE_x_w*(CIE_y_r - CIE_y_g) - \
253 CIE_y_w*(CIE_x_r - CIE_x_g) + \
254 CIE_x_r*CIE_y_g - CIE_x_g*CIE_y_r ) )
255
256 #define CIE_rf (CIE_y_r*CIE_C_rD/CIE_D)
257 #define CIE_gf (CIE_y_g*CIE_C_gD/CIE_D)
258 #define CIE_bf (CIE_y_b*CIE_C_bD/CIE_D)
259
260 /* As of 9-94, CIE_rf=.265074126, CIE_gf=.670114631 and CIE_bf=.064811243 */
261
262 /***** The following definitions are valid for RGB colors only... *****/
263
264 #define bright(col) (CIE_rf*(col)[RED]+CIE_gf*(col)[GRN]+CIE_bf*(col)[BLU])
265 #define normbright(c) ( ( (long)(CIE_rf*256.+.5)*(c)[RED] + \
266 (long)(CIE_gf*256.+.5)*(c)[GRN] + \
267 (long)(CIE_bf*256.+.5)*(c)[BLU] ) >> 8 )
268
269 /* luminous efficacies over visible spectrum */
270 #define MAXEFFICACY 683. /* defined maximum at 550 nm */
271 #define WHTEFFICACY 179. /* uniform white light */
272 #define D65EFFICACY 203. /* standard illuminant D65 */
273 #define INCEFFICACY 160. /* illuminant A (incand.) */
274 #define SUNEFFICACY 208. /* illuminant B (solar dir.) */
275 #define SKYEFFICACY D65EFFICACY /* skylight (should be 110) */
276 #define DAYEFFICACY D65EFFICACY /* combined sky and solar */
277
278 #define luminance(col) (WHTEFFICACY * bright(col))
279
280 /***** ...end of stuff specific to RGB colors *****/
281
282 #define intens(col) ( (col)[0] > (col)[1] \
283 ? (col)[0] > (col)[2] ? (col)[0] : (col)[2] \
284 : (col)[1] > (col)[2] ? (col)[1] : (col)[2] )
285
286 #define colrval(c,p) ( (c)[EXP] ? \
287 ldexp((c)[p]+.5,(int)(c)[EXP]-(COLXS+8)) : \
288 0. )
289
290 #define WHTCOLOR {1.0,1.0,1.0}
291 #define BLKCOLOR {0.0,0.0,0.0}
292 #define WHTCOLR {128,128,128,COLXS+1}
293 #define BLKCOLR {0,0,0,0}
294
295 /* picture format identifier */
296 #define COLRFMT "32-bit_rle_rgbe"
297 #define CIEFMT "32-bit_rle_xyze"
298 #define PICFMT "32-bit_rle_???e" /* matches either */
299 #define LPICFMT 15 /* max format id len */
300
301 /* macros for exposures */
302 #define EXPOSSTR "EXPOSURE="
303 #define LEXPOSSTR 9
304 #define isexpos(hl) (!strncmp(hl,EXPOSSTR,LEXPOSSTR))
305 #define exposval(hl) atof((hl)+LEXPOSSTR)
306 #define fputexpos(ex,fp) fprintf(fp,"%s%e\n",EXPOSSTR,ex)
307
308 /* macros for pixel aspect ratios */
309 #define ASPECTSTR "PIXASPECT="
310 #define LASPECTSTR 10
311 #define isaspect(hl) (!strncmp(hl,ASPECTSTR,LASPECTSTR))
312 #define aspectval(hl) atof((hl)+LASPECTSTR)
313 #define fputaspect(pa,fp) fprintf(fp,"%s%f\n",ASPECTSTR,pa)
314
315 /* macros for primary specifications */
316 #define PRIMARYSTR "PRIMARIES="
317 #define LPRIMARYSTR 10
318 #define isprims(hl) (!strncmp(hl,PRIMARYSTR,LPRIMARYSTR))
319 #define primsval(p,hl) (sscanf((hl)+LPRIMARYSTR, \
320 "%f %f %f %f %f %f %f %f", \
321 &(p)[RED][CIEX],&(p)[RED][CIEY], \
322 &(p)[GRN][CIEX],&(p)[GRN][CIEY], \
323 &(p)[BLU][CIEX],&(p)[BLU][CIEY], \
324 &(p)[WHT][CIEX],&(p)[WHT][CIEY]) == 8)
325 #define fputprims(p,fp) fprintf(fp, \
326 "%s %.4f %.4f %.4f %.4f %.4f %.4f %.4f %.4f\n",\
327 PRIMARYSTR, \
328 (p)[RED][CIEX],(p)[RED][CIEY], \
329 (p)[GRN][CIEX],(p)[GRN][CIEY], \
330 (p)[BLU][CIEX],(p)[BLU][CIEY], \
331 (p)[WHT][CIEX],(p)[WHT][CIEY])
332
333 /* macros for color correction */
334 #define COLCORSTR "COLORCORR="
335 #define LCOLCORSTR 10
336 #define iscolcor(hl) (!strncmp(hl,COLCORSTR,LCOLCORSTR))
337 #define colcorval(cc,hl) sscanf((hl)+LCOLCORSTR,"%f %f %f", \
338 &(cc)[RED],&(cc)[GRN],&(cc)[BLU])
339 #define fputcolcor(cc,fp) fprintf(fp,"%s %f %f %f\n",COLCORSTR, \
340 (cc)[RED],(cc)[GRN],(cc)[BLU])
341
342 /*
343 * Conversions to and from XYZ space generally don't apply WHTEFFICACY.
344 * If you need Y to be luminance (cd/m^2), this must be applied when
345 * converting from radiance (watts/sr/m^2).
346 */
347
348 extern RGBPRIMS stdprims; /* standard primary chromaticities */
349 extern COLORMAT rgb2xyzmat; /* RGB to XYZ conversion matrix */
350 extern COLORMAT xyz2rgbmat; /* XYZ to RGB conversion matrix */
351 extern COLOR cblack, cwhite; /* black (0,0,0) and white (1,1,1) */
352
353 #define CGAMUT_LOWER 01
354 #define CGAMUT_UPPER 02
355 #define CGAMUT (CGAMUT_LOWER|CGAMUT_UPPER)
356
357 #define rgb_cie(xyz,rgb) colortrans(xyz,rgb2xyzmat,rgb)
358
359 #define cpcolormat(md,ms) memcpy((void *)md,(void *)ms,sizeof(COLORMAT))
360
361 #ifdef getc_unlocked /* avoid horrendous overhead of flockfile */
362 #undef getc
363 #undef putc
364 #define getc getc_unlocked
365 #define putc putc_unlocked
366 #endif
367
368 #define MINELEN 8 /* minimum scanline length for encoding */
369 #define MAXELEN 0x7fff /* maximum scanline length for encoding */
370 #define MINRUN 4 /* minimum run length */
371
372 /* flags for scanline ordering */
373 #define XDECR 1
374 #define YDECR 2
375 #define YMAJOR 4
376
377 /* standard scanline ordering */
378 #define PIXSTANDARD (YMAJOR|YDECR)
379 #define PIXSTDFMT "-Y %d +X %d\n"
380
381 /* structure for image dimensions */
382 typedef struct {
383 int rt; /* orientation (from flags above) */
384 int xr, yr; /* x and y resolution */
385 } RESOLU;
386
387 /* macros to get scanline length and number */
388 #define scanlen(rs) ((rs)->rt & YMAJOR ? (rs)->xr : (rs)->yr)
389 #define numscans(rs) ((rs)->rt & YMAJOR ? (rs)->yr : (rs)->xr)
390
391 /* resolution string buffer and its size */
392 #define RESOLU_BUFLEN 32
393
394 /* macros for reading/writing resolution struct */
395 #define fputsresolu(rs,fp) fputs(resolu2str(resolu_buf,rs),fp)
396 #define fgetsresolu(rs,fp) str2resolu(rs, \
397 fgets(resolu_buf,RESOLU_BUFLEN,fp))
398
399 /* reading/writing of standard ordering */
400 #define fprtresolu(sl,ns,fp) fprintf(fp,PIXSTDFMT,ns,sl)
401 #define fscnresolu(sl,ns,fp) (fscanf(fp,PIXSTDFMT,ns,sl)==2)
402
403 /* identify header lines */
404 #define isheadid(s) headidval(NULL,s)
405 #define isformat(s) formatval(NULL,s)
406 #define isdate(s) dateval(NULL,s)
407 #define isgmt(s) gmtval(NULL,s)
408
409 #define LATLONSTR "LATLONG="
410 #define LLATLONSTR 8
411 #define islatlon(hl) (!strncmp(hl,LATLONSTR,LLATLONSTR))
412 #define latlonval(ll,hl) sscanf((hl)+LLATLONSTR, "%f %f", \
413 &(ll)[0],&(ll)[1])
414 #define fputlatlon(lat,lon,fp) fprintf(fp,"%s %.6f %.6f\n",LATLONSTR,lat,lon)
415
416 typedef int gethfunc(char *s, void *p); /* callback to process header lines */
417
418 #ifdef getc_unlocked /* avoid horrendous overhead of flockfile */
419 #undef getc
420 #undef putc
421 #define getc getc_unlocked
422 #define putc putc_unlocked
423 #endif
424
425
426 static char resolu_buf[RESOLU_BUFLEN]; /* resolution line buffer */
427
428 static char *
resolu2str(buf,rp)429 resolu2str(buf, rp) /* convert resolution struct to line */
430 char *buf;
431 register RESOLU *rp;
432 {
433 if (rp->rt&YMAJOR)
434 sprintf(buf, "%cY %d %cX %d\n",
435 rp->rt&YDECR ? '-' : '+', rp->yr,
436 rp->rt&XDECR ? '-' : '+', rp->xr);
437 else
438 sprintf(buf, "%cX %d %cY %d\n",
439 rp->rt&XDECR ? '-' : '+', rp->xr,
440 rp->rt&YDECR ? '-' : '+', rp->yr);
441 return(buf);
442 }
443
444
445 static int
str2resolu(rp,buf)446 str2resolu(rp, buf) /* convert resolution line to struct */
447 register RESOLU *rp;
448 char *buf;
449 {
450 register char *xndx, *yndx;
451 register char *cp;
452
453 if (buf == NULL)
454 return(0);
455 xndx = yndx = NULL;
456 for (cp = buf; *cp; cp++)
457 if (*cp == 'X')
458 xndx = cp;
459 else if (*cp == 'Y')
460 yndx = cp;
461 if (xndx == NULL || yndx == NULL)
462 return(0);
463 rp->rt = 0;
464 if (xndx > yndx) rp->rt |= YMAJOR;
465 if (xndx[-1] == '-') rp->rt |= XDECR;
466 if (yndx[-1] == '-') rp->rt |= YDECR;
467 if ((rp->xr = atoi(xndx+1)) <= 0)
468 return(0);
469 if ((rp->yr = atoi(yndx+1)) <= 0)
470 return(0);
471 return(1);
472 }
473
474 #define MAXLINE 2048
475 #define MAXFMTLEN 2048
476
477 static const char FMTSTR[] = "FORMAT="; /* format identifier */
478
479
480 static int
formatval(char fmt[MAXFMTLEN],const char * s)481 formatval( /* get format value (return true if format) */
482 char fmt[MAXFMTLEN],
483 const char *s
484 )
485 {
486 const char *cp = FMTSTR;
487 char *r = fmt;
488
489 while (*cp) if (*cp++ != *s++) return(0);
490 while (isspace(*s)) s++;
491 if (!*s) return(0);
492 if (r == NULL) return(1);
493 do
494 *r++ = *s++;
495 while (*s && !isspace(*s) && r-fmt < MAXFMTLEN-1);
496 *r = '\0';
497 return(1);
498 }
499
500
501 static int
getheader(VipsSbuf * sbuf,gethfunc * f,void * p)502 getheader( /* get header from file */
503 VipsSbuf *sbuf,
504 gethfunc *f,
505 void *p
506 )
507 {
508 for(;;) {
509 const char *line;
510
511 if( !(line = vips_sbuf_get_line( sbuf )) )
512 return( -1 );
513 if( strcmp( line, "" ) == 0 )
514 /* Blank line. We've parsed the header successfully.
515 */
516 break;
517
518 if( f != NULL &&
519 (*f)( (char *) line, p ) < 0 )
520 return( -1 );
521 }
522
523 return( 0 );
524 }
525
526 /* Read a single scanline, encoded in the old style.
527 */
528 static int
scanline_read_old(VipsSbuf * sbuf,COLR * scanline,int width)529 scanline_read_old( VipsSbuf *sbuf, COLR *scanline, int width )
530 {
531 int rshift;
532
533 rshift = 0;
534
535 while( width > 0 ) {
536 if( VIPS_SBUF_REQUIRE( sbuf, 4 ) )
537 return( -1 );
538
539 scanline[0][RED] = VIPS_SBUF_FETCH( sbuf );
540 scanline[0][GRN] = VIPS_SBUF_FETCH( sbuf );
541 scanline[0][BLU] = VIPS_SBUF_FETCH( sbuf );
542 scanline[0][EXP] = VIPS_SBUF_FETCH( sbuf );
543
544 if( scanline[0][RED] == 1 &&
545 scanline[0][GRN] == 1 &&
546 scanline[0][BLU] == 1 ) {
547 guint i;
548
549 for( i = ((guint32) scanline[0][EXP] << rshift);
550 i > 0 && width > 0; i-- ) {
551 copycolr( scanline[0], scanline[-1] );
552 scanline += 1;
553 width -= 1;
554 }
555
556 rshift += 8;
557
558 /* This can happen with badly-formed input files.
559 */
560 if( rshift > 24 )
561 return( -1 );
562 }
563 else {
564 scanline += 1;
565 width -= 1;
566 rshift = 0;
567 }
568 }
569
570 return( 0 );
571 }
572
573 /* Read a single encoded scanline.
574 */
575 static int
scanline_read(VipsSbuf * sbuf,COLR * scanline,int width)576 scanline_read( VipsSbuf *sbuf, COLR *scanline, int width )
577 {
578 int i, j;
579
580 /* Detect old-style scanlines.
581 */
582 if( width < MINELEN ||
583 width > MAXELEN )
584 return( scanline_read_old( sbuf, scanline, width ) );
585
586 if( VIPS_SBUF_REQUIRE( sbuf, 4 ) )
587 return( -1 );
588
589 if( VIPS_SBUF_PEEK( sbuf )[0] != 2 )
590 return( scanline_read_old( sbuf, scanline, width ) );
591
592 scanline[0][RED] = VIPS_SBUF_FETCH( sbuf );
593 scanline[0][GRN] = VIPS_SBUF_FETCH( sbuf );
594 scanline[0][BLU] = VIPS_SBUF_FETCH( sbuf );
595 scanline[0][EXP] = VIPS_SBUF_FETCH( sbuf );
596 if( scanline[0][GRN] != 2 ||
597 scanline[0][BLU] & 128 )
598 return( scanline_read_old( sbuf,
599 scanline + 1, width - 1 ) );
600
601 if( ((scanline[0][BLU] << 8) | scanline[0][EXP]) != width ) {
602 vips_error( "rad2vips", "%s", _( "scanline length mismatch" ) );
603 return( -1 );
604 }
605
606 for( i = 0; i < 4; i++ )
607 for( j = 0; j < width; ) {
608 int code, len;
609 gboolean run;
610
611 if( VIPS_SBUF_REQUIRE( sbuf, 2 ) )
612 return( -1 );
613
614 code = VIPS_SBUF_FETCH( sbuf );
615 run = code > 128;
616 len = run ? code & 127 : code;
617
618 if( j + len > width ) {
619 vips_error( "rad2vips", "%s", _( "overrun" ) );
620 return( -1 );
621 }
622
623 if( run ) {
624 int val;
625
626 val = VIPS_SBUF_FETCH( sbuf );
627 while( len-- )
628 scanline[j++][i] = val;
629 }
630 else {
631 if( VIPS_SBUF_REQUIRE( sbuf, len ) )
632 return( -1 );
633 while( len-- )
634 scanline[j++][i] =
635 VIPS_SBUF_FETCH( sbuf );
636 }
637 }
638
639 return( 0 );
640 }
641
642 /* An encoded scanline can't be larger than this.
643 */
644 #define MAX_LINE (2 * MAXELEN * sizeof( COLR ))
645
646 /* write an RLE scanline. Write magic header.
647 */
648 static void
rle_scanline_write(COLR * scanline,int width,unsigned char * buffer,int * length)649 rle_scanline_write( COLR *scanline, int width,
650 unsigned char *buffer, int *length )
651 {
652 int i, j, beg, cnt;
653
654 #define PUTC( CH ) { \
655 buffer[(*length)++] = (CH); \
656 g_assert( *length <= MAX_LINE ); \
657 }
658
659 *length = 0;
660
661 PUTC( 2 );
662 PUTC( 2 );
663 PUTC( width >> 8 );
664 PUTC( width & 255 );
665
666 for( i = 0; i < 4; i++ ) {
667 for( j = 0; j < width; ) {
668 /* Not needed, but keeps gcc used-before-set warning
669 * quiet.
670 */
671 cnt = 1;
672
673 /* Set beg / cnt to the start and length of the next
674 * run longer than MINRUN.
675 */
676 for( beg = j; beg < width; beg += cnt ) {
677 for( cnt = 1;
678 cnt < 127 &&
679 beg + cnt < width &&
680 scanline[beg + cnt][i] ==
681 scanline[beg][i];
682 cnt++ )
683 ;
684
685 if( cnt >= MINRUN )
686 break;
687 }
688
689 /* Code pixels leading up to the run as a set of
690 * non-runs.
691 */
692 while( j < beg ) {
693 int len = VIPS_MIN( 128, beg - j );
694 COLR *p = scanline + j;
695
696 int k;
697
698 PUTC( len );
699 for( k = 0; k < len; k++ )
700 PUTC( p[k][i] );
701 j += len;
702 }
703
704 /* Code the run we found, if any
705 */
706 if( cnt >= MINRUN ) {
707 PUTC( 128 + cnt );
708 PUTC( scanline[j][i] );
709 j += cnt;
710 }
711 }
712 }
713 }
714
715 /* What we track during radiance file read.
716 */
717 typedef struct {
718 VipsSbuf *sbuf;
719 VipsImage *out;
720
721 char format[256];
722 double expos;
723 COLOR colcor;
724 double aspect;
725 RGBPRIMS prims;
726 RESOLU rs;
727 } Read;
728
729 int
vips__rad_israd(VipsSource * source)730 vips__rad_israd( VipsSource *source )
731 {
732 VipsSbuf *sbuf;
733 const char *line;
734 int result;
735
736 /* Just test that the first line is the magic string.
737 */
738 sbuf = vips_sbuf_new_from_source( source );
739 result = (line = vips_sbuf_get_line( sbuf )) &&
740 strcmp( line, "#?RADIANCE" ) == 0;
741 VIPS_UNREF( sbuf );
742
743 return( result );
744 }
745
746 static void
read_destroy(VipsImage * image,Read * read)747 read_destroy( VipsImage *image, Read *read )
748 {
749 VIPS_UNREF( read->sbuf );
750 }
751
752 static void
read_minimise_cb(VipsImage * image,Read * read)753 read_minimise_cb( VipsImage *image, Read *read )
754 {
755 if( read->sbuf )
756 vips_source_minimise( read->sbuf->source );
757 }
758
759 static Read *
read_new(VipsSource * source,VipsImage * out)760 read_new( VipsSource *source, VipsImage *out )
761 {
762 Read *read;
763 int i;
764
765 if( vips_source_rewind( source ) )
766 return( NULL );
767
768 if( !(read = VIPS_NEW( out, Read )) )
769 return( NULL );
770
771 read->sbuf = vips_sbuf_new_from_source( source );
772 read->out = out;
773 strcpy( read->format, COLRFMT );
774 read->expos = 1.0;
775 for( i = 0; i < 3; i++ )
776 read->colcor[i] = 1.0;
777 read->aspect = 1.0;
778 read->prims[0][0] = CIE_x_r;
779 read->prims[0][1] = CIE_y_r;
780 read->prims[1][0] = CIE_x_g;
781 read->prims[1][1] = CIE_y_g;
782 read->prims[2][0] = CIE_x_b;
783 read->prims[2][1] = CIE_y_b;
784 read->prims[3][0] = CIE_x_w;
785 read->prims[3][1] = CIE_y_w;
786
787 g_signal_connect( out, "close",
788 G_CALLBACK( read_destroy ), read );
789 g_signal_connect( out, "minimise",
790 G_CALLBACK( read_minimise_cb ), read );
791
792 return( read );
793 }
794
795 static int
rad2vips_process_line(char * line,Read * read)796 rad2vips_process_line( char *line, Read *read )
797 {
798 if( isformat( line ) ) {
799 if( formatval( line, read->format ) )
800 return( -1 );
801 }
802 else if( isexpos( line ) ) {
803 read->expos *= exposval( line );
804 }
805 else if( iscolcor( line ) ) {
806 COLOR cc;
807 int i;
808
809 (void) colcorval( cc, line );
810 for( i = 0; i < 3; i++ )
811 read->colcor[i] *= cc[i];
812 }
813 else if( isaspect( line ) ) {
814 read->aspect *= aspectval( line );
815 }
816 else if( isprims( line ) ) {
817 (void) primsval( read->prims, line );
818 }
819
820 return( 0 );
821 }
822
823 static const char *prims_name[4][2] = {
824 { "rad-prims-rx", "rad-prims-ry" },
825 { "rad-prims-gx", "rad-prims-gy" },
826 { "rad-prims-bx", "rad-prims-by" },
827 { "rad-prims-wx", "rad-prims-wy" }
828 };
829
830 static const char *colcor_name[3] = {
831 "rad-colcor-r",
832 "rad-colcor-g",
833 "rad-colcor-b"
834 };
835
836 static int
rad2vips_get_header(Read * read,VipsImage * out)837 rad2vips_get_header( Read *read, VipsImage *out )
838 {
839 VipsInterpretation interpretation;
840 const char *line;
841 int width;
842 int height;
843 int i, j;
844
845 if( getheader( read->sbuf,
846 (gethfunc *) rad2vips_process_line, read ) ||
847 !(line = vips_sbuf_get_line( read->sbuf )) ||
848 !str2resolu( &read->rs, (char *) line ) ) {
849 vips_error( "rad2vips", "%s",
850 _( "error reading radiance header" ) );
851 return( -1 );
852 }
853
854 if( strcmp( read->format, COLRFMT ) == 0 )
855 interpretation = VIPS_INTERPRETATION_scRGB;
856 else if( strcmp( read->format, CIEFMT ) == 0 )
857 interpretation = VIPS_INTERPRETATION_XYZ;
858 else
859 interpretation = VIPS_INTERPRETATION_MULTIBAND;
860
861 width = scanlen( &read->rs );
862 height = numscans( &read->rs );
863 if( width <= 0 ||
864 width >= VIPS_MAX_COORD ||
865 height <= 0 ||
866 height >= VIPS_MAX_COORD ) {
867 vips_error( "rad2vips", "%s", _( "image size out of bounds" ) );
868 return( -1 );
869 }
870
871 vips_image_init_fields( out, width, height, 4,
872 VIPS_FORMAT_UCHAR, VIPS_CODING_RAD,
873 interpretation,
874 1, read->aspect );
875
876 VIPS_SETSTR( out->filename,
877 vips_connection_filename(
878 VIPS_CONNECTION( read->sbuf->source ) ) );
879
880 if( vips_image_pipelinev( out, VIPS_DEMAND_STYLE_THINSTRIP, NULL ) )
881 return( -1 );
882
883 vips_image_set_string( out, "rad-format", read->format );
884
885 vips_image_set_double( out, "rad-expos", read->expos );
886
887 for( i = 0; i < 3; i++ )
888 vips_image_set_double( out,
889 colcor_name[i], read->colcor[i] );
890
891 vips_image_set_double( out, "rad-aspect", read->aspect );
892
893 for( i = 0; i < 4; i++ )
894 for( j = 0; j < 2; j++ )
895 vips_image_set_double( out,
896 prims_name[i][j], read->prims[i][j] );
897
898 return( 0 );
899 }
900
901 int
vips__rad_header(VipsSource * source,VipsImage * out)902 vips__rad_header( VipsSource *source, VipsImage *out )
903 {
904 Read *read;
905
906 if( !(read = read_new( source, out )) )
907 return( -1 );
908 if( rad2vips_get_header( read, read->out ) )
909 return( -1 );
910 vips_source_minimise( source );
911
912 return( 0 );
913 }
914
915 static int
rad2vips_generate(VipsRegion * or,void * seq,void * a,void * b,gboolean * stop)916 rad2vips_generate( VipsRegion *or,
917 void *seq, void *a, void *b, gboolean *stop )
918 {
919 VipsRect *r = &or->valid;
920 Read *read = (Read *) a;
921
922 int y;
923
924 #ifdef DEBUG
925 printf( "rad2vips_generate: line %d, %d rows\n",
926 r->top, r->height );
927 #endif /*DEBUG*/
928
929 VIPS_GATE_START( "rad2vips_generate: work" );
930
931 for( y = 0; y < r->height; y++ ) {
932 COLR *buf = (COLR *)
933 VIPS_REGION_ADDR( or, 0, r->top + y );
934
935 if( scanline_read( read->sbuf, buf, or->im->Xsize ) ) {
936 vips_error( "rad2vips",
937 _( "read error line %d" ), r->top + y );
938 VIPS_GATE_STOP( "rad2vips_generate: work" );
939 return( -1 );
940 }
941 }
942
943 VIPS_GATE_STOP( "rad2vips_generate: work" );
944
945 return( 0 );
946 }
947
948 int
vips__rad_load(VipsSource * source,VipsImage * out)949 vips__rad_load( VipsSource *source, VipsImage *out )
950 {
951 VipsImage **t = (VipsImage **)
952 vips_object_local_array( VIPS_OBJECT( out ), 3 );
953
954 Read *read;
955
956 #ifdef DEBUG
957 printf( "rad2vips: reading \"%s\"\n",
958 vips_connection_nick( VIPS_CONNECTION( source ) ) );
959 #endif /*DEBUG*/
960
961 if( !(read = read_new( source, out )) )
962 return( -1 );
963
964 t[0] = vips_image_new();
965 if( rad2vips_get_header( read, t[0] ) )
966 return( -1 );
967
968 if( vips_image_generate( t[0],
969 NULL, rad2vips_generate, NULL, read, NULL ) ||
970 vips_sequential( t[0], &t[1],
971 "tile_height", VIPS__FATSTRIP_HEIGHT,
972 NULL ) ||
973 vips_image_write( t[1], out ) )
974 return( -1 );
975
976 if( vips_source_decode( source ) )
977 return( -1 );
978
979 return( 0 );
980 }
981
982 /* What we track during a radiance write.
983 */
984 typedef struct {
985 VipsImage *in;
986 VipsTarget *target;
987
988 char format[256];
989 double expos;
990 COLOR colcor;
991 double aspect;
992 RGBPRIMS prims;
993 RESOLU rs;
994 unsigned char *line;
995 } Write;
996
997 static void
write_destroy(Write * write)998 write_destroy( Write *write )
999 {
1000 VIPS_FREE( write->line );
1001 VIPS_UNREF( write->target );
1002
1003 g_free( write );
1004 }
1005
1006 static Write *
write_new(VipsImage * in,VipsTarget * target)1007 write_new( VipsImage *in, VipsTarget *target )
1008 {
1009 Write *write;
1010 int i;
1011
1012 if( !(write = VIPS_NEW( NULL, Write )) )
1013 return( NULL );
1014
1015 write->in = in;
1016 write->target = target;
1017 g_object_ref( target );
1018
1019 strcpy( write->format, COLRFMT );
1020 write->expos = 1.0;
1021 for( i = 0; i < 3; i++ )
1022 write->colcor[i] = 1.0;
1023 write->aspect = 1.0;
1024 write->prims[0][0] = CIE_x_r;
1025 write->prims[0][1] = CIE_y_r;
1026 write->prims[1][0] = CIE_x_g;
1027 write->prims[1][1] = CIE_y_g;
1028 write->prims[2][0] = CIE_x_b;
1029 write->prims[2][1] = CIE_y_b;
1030 write->prims[3][0] = CIE_x_w;
1031 write->prims[3][1] = CIE_y_w;
1032
1033 if( !(write->line = VIPS_ARRAY( NULL, MAX_LINE, unsigned char )) ) {
1034 write_destroy( write );
1035 return( NULL );
1036 }
1037
1038 return( write );
1039 }
1040
1041 static void
vips2rad_make_header(Write * write)1042 vips2rad_make_header( Write *write )
1043 {
1044 const char *str;
1045 int i, j;
1046 double d;
1047
1048 if( vips_image_get_typeof( write->in, "rad-expos" ) )
1049 vips_image_get_double( write->in, "rad-expos", &write->expos );
1050
1051 if( vips_image_get_typeof( write->in, "rad-aspect" ) )
1052 vips_image_get_double( write->in,
1053 "rad-aspect", &write->aspect );
1054
1055 if( vips_image_get_typeof( write->in, "rad-format" ) &&
1056 !vips_image_get_string( write->in, "rad-format", &str ) )
1057 vips_strncpy( write->format, str, 256 );
1058
1059 if( write->in->Type == VIPS_INTERPRETATION_scRGB )
1060 strcpy( write->format, COLRFMT );
1061 if( write->in->Type == VIPS_INTERPRETATION_XYZ )
1062 strcpy( write->format, CIEFMT );
1063
1064 for( i = 0; i < 3; i++ )
1065 if( vips_image_get_typeof( write->in, colcor_name[i] ) &&
1066 !vips_image_get_double( write->in,
1067 colcor_name[i], &d ) )
1068 write->colcor[i] = d;
1069
1070 for( i = 0; i < 4; i++ )
1071 for( j = 0; j < 2; j++ ) {
1072 const char *name = prims_name[i][j];
1073
1074 if( vips_image_get_typeof( write->in, name ) &&
1075 !vips_image_get_double( write->in, name, &d ) )
1076 write->prims[i][j] = d;
1077 }
1078
1079 /* Make y decreasing for consistency with vips.
1080 */
1081 write->rs.rt = YDECR | YMAJOR;
1082 write->rs.xr = write->in->Xsize;
1083 write->rs.yr = write->in->Ysize;
1084 }
1085
1086 static int
vips2rad_put_header(Write * write)1087 vips2rad_put_header( Write *write )
1088 {
1089 vips2rad_make_header( write );
1090
1091 vips_target_writes( write->target, "#?RADIANCE\n" );
1092 vips_target_writef( write->target, "%s%s\n", FMTSTR, write->format );
1093 vips_target_writef( write->target, "%s%e\n", EXPOSSTR, write->expos );
1094 vips_target_writef( write->target,
1095 "%s %f %f %f\n", COLCORSTR,
1096 write->colcor[RED], write->colcor[GRN], write->colcor[BLU] );
1097 vips_target_writef( write->target,
1098 "SOFTWARE=vips %s\n", vips_version_string() );
1099 vips_target_writef( write->target,
1100 "%s%f\n", ASPECTSTR, write->aspect );
1101 vips_target_writef( write->target,
1102 "%s %.4f %.4f %.4f %.4f %.4f %.4f %.4f %.4f\n",
1103 PRIMARYSTR,
1104 write->prims[RED][CIEX], write->prims[RED][CIEY],
1105 write->prims[GRN][CIEX], write->prims[GRN][CIEY],
1106 write->prims[BLU][CIEX], write->prims[BLU][CIEY],
1107 write->prims[WHT][CIEX], write->prims[WHT][CIEY] );
1108 vips_target_writes( write->target, "\n" );
1109 vips_target_writes( write->target,
1110 resolu2str( resolu_buf, &write->rs ) );
1111
1112 return( 0 );
1113 }
1114
1115 /* Write a single scanline to buffer.
1116 */
1117 static int
scanline_write(Write * write,COLR * scanline,int width)1118 scanline_write( Write *write, COLR *scanline, int width )
1119 {
1120 if( width < MINELEN ||
1121 width > MAXELEN ) {
1122 /* Too large or small for RLE ... do a simple write.
1123 */
1124 if( vips_target_write( write->target,
1125 scanline, sizeof( COLR ) * width ) )
1126 return( -1 );
1127 }
1128 else {
1129 int length;
1130
1131 /* An RLE scanline.
1132 */
1133 rle_scanline_write( scanline, width, write->line, &length );
1134
1135 if( vips_target_write( write->target, write->line, length ) )
1136 return( -1 );
1137 }
1138
1139 return( 0 );
1140 }
1141
1142 static int
vips2rad_put_data_block(VipsRegion * region,VipsRect * area,void * a)1143 vips2rad_put_data_block( VipsRegion *region, VipsRect *area, void *a )
1144 {
1145 Write *write = (Write *) a;
1146 int i;
1147
1148 for( i = 0; i < area->height; i++ ) {
1149 VipsPel *p = VIPS_REGION_ADDR( region, 0, area->top + i );
1150
1151 if( scanline_write( write, (COLR *) p, area->width ) )
1152 return( -1 );
1153 }
1154
1155 return( 0 );
1156 }
1157
1158 static int
vips2rad_put_data(Write * write)1159 vips2rad_put_data( Write *write )
1160 {
1161 if( vips_sink_disc( write->in, vips2rad_put_data_block, write ) )
1162 return( -1 );
1163
1164 return( 0 );
1165 }
1166
1167 int
vips__rad_save(VipsImage * in,VipsTarget * target)1168 vips__rad_save( VipsImage *in, VipsTarget *target )
1169 {
1170 Write *write;
1171
1172 #ifdef DEBUG
1173 printf( "vips2rad: writing to buffer\n" );
1174 #endif /*DEBUG*/
1175
1176 if( vips_image_pio_input( in ) ||
1177 vips_check_coding( "vips2rad", in, VIPS_CODING_RAD ) )
1178 return( -1 );
1179 if( !(write = write_new( in, target )) )
1180 return( -1 );
1181
1182 if( vips2rad_put_header( write ) ||
1183 vips2rad_put_data( write ) ) {
1184 write_destroy( write );
1185 return( -1 );
1186 }
1187
1188 vips_target_finish( target );
1189
1190 write_destroy( write );
1191
1192 return( 0 );
1193 }
1194
1195 const char *vips__rad_suffs[] = { ".hdr", NULL };
1196
1197 #endif /*HAVE_RADIANCE*/
1198