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