1 /* dip.c
2 * Digital Image Processing routines
3 * (c) 2000-2002 Karel 'Clock' Kulhavy
4 * This file is a part of the Links program, released under GPL.
5 * This does various utilities for digital image processing including font
6 * rendering.
7 */
8
9 #include "cfg.h"
10
11 #ifdef G
12
13 #include "links.h"
14
15 #ifdef HAVE_MATH_H
16 #include <math.h>
17 #endif /* HAVE_MATH_H */
18
19 /* #define this if you want to report missing letters to stderr.
20 * Leave it commented up for normal operation and releases! */
21 /* #define REPORT_UNKNOWN 1 */
22
23 unsigned aspect=65536; /* aspect=65536 for 320x240
24 * aspect=157286 for 640x200 (tall pixels)
25 * Defines aspect ratio of screen pixels.
26 * aspect=(196608*xsize+ysize<<1)/(ysize<<1);
27 * Default is 65536 because we assume square pixel
28 * when not specified otherwise. Aspect is ratio of
29 * the pixel height (in milimeters) to pixel width,
30 * multiplied by 65536. */
31
32 /* Limitation: No input image's dimension may exceed 2^(32-1-8) pixels.
33 */
34
35 /* Each input byte represents 1 byte (gray). The question whether 0 is
36 * black or 255 is black doesn't matter.
37 */
38
39 /* These constants represent contrast-enhancement and sharpen filter (which is one filter
40 * together) that is applied onto the letters to enhance their appearance at low height.
41 * They were determined by experiment for several values, interpolated, checked and tuned.
42 * If you change them, don't wonder if the letters start to look strange.
43 * The numers in the comments denote which height the line applies for.
44 */
45 static_const float fancy_constants[64]={
46 (float)0,(float)3, /* 1 */
47 (float).1,(float)3, /* 2 */
48 (float).2,(float)3, /* 3 */
49 (float).3,(float)2.9, /* 4 */
50 (float).4,(float)2.7, /* 5 */
51 (float).4,(float)2.5, /* 6 */
52 (float).4,(float)2, /* 7 */
53 (float).5,(float)2, /* 8 */
54 (float).4,(float)2, /* 9 */
55 (float).38,(float)1.9, /* 10 */
56 (float).36,(float)1.8, /* 11 */
57 (float).33,(float)1.7, /* 12 */
58 (float).30,(float)1.6, /* 13 */
59 (float).25,(float)1.5, /* 14 */
60 (float).20,(float)1.5, /* 15 */
61 (float).15,(float)1.5, /* 16 */
62 (float).14,(float)1.5, /* 17 */
63 (float).13,(float)1.5, /* 18 */
64 (float).12,(float)1.5, /* 19 */
65 (float).12,(float)1.5, /* 20 */
66 (float).12,(float)1.5, /* 21 */
67 (float).12,(float)1.5, /* 22 */
68 (float).11,(float)1.5, /* 23 */
69 (float).10,(float)1.4, /* 24 */
70 (float).09,(float)1.3, /* 25 */
71 (float).08,(float)1.3, /* 26 */
72 (float).04,(float)1.2, /* 27 */
73 (float).04,(float)1.2, /* 28 */
74 (float).02,(float)1.1, /* 29 */
75 (float).02,(float)1.1, /* 30 */
76 (float).01,(float)1, /* 31 */
77 (float).01,(float)1 /* 32 */
78 };
79
80
81 /* This shall be hopefully reasonably fast and portable
82 * We assume ix is <65536. If not, the letters will be smaller in
83 * horizontal dimension (because of overflow) but this will not cause
84 * a segfault. 65536 pixels wide bitmaps are not normal and will anyway
85 * exhaust the memory.
86 */
compute_width(int ix,int iy,int required_height)87 int compute_width(int ix, int iy, int required_height)
88 {
89 int width;
90 unsigned long reg;
91
92 reg=(unsigned long)aspect*(unsigned long)required_height;
93
94 if (reg>=0x1000000UL) {
95 /* It's big */
96 reg=(reg+32768)>>16;
97 width=(int)((reg*ix+(iy>>1))/iy);
98 }else{
99 /* It's small */
100 reg=(reg+128)>>8;
101 iy<<=8;
102 width=(int)((reg*ix+(iy>>1))/iy);
103 }
104 if (width<1) width=1;
105 return width;
106 }
107
108 static struct lru font_cache;
109 /* This is a cache for screen-ready colored bitmaps
110 * of lettrs and/or alpha channels for these (are the
111 * same size, only one byte per pixel and are used
112 * for letters with an image under them )
113 */
114
115 #if defined(__i686__) || defined(__athlon__) || defined(__SSE2__) || defined(__x86_64__) || defined(__aarch64__) || defined(__alpha) || defined(__hppa)
116 /*
117 * On modern processors it is faster to do this in floating point.
118 * Do it only if we are sure that the coprocessor is present.
119 */
120 typedef double scale_t;
121 #define USE_FP_SCALE
122 #elif defined(HAVE_LONG_LONG)
123 typedef unsigned long long scale_t;
124 #else
125 /*
126 * This may overflow, but systems without long long are very old
127 * and we will rather accept overflow on big images (65536 pixels)
128 * than slowing down the process unacceptably with possibly emulated FPU.
129 */
130 typedef unsigned long scale_t;
131 #endif
132
133 /* Each input byte represents 1 byte (gray). The question whether 0 is
134 * black or 255 is black doesn't matter.
135 */
136
add_col_gray(unsigned * my_restrict col_buf,unsigned char * my_restrict ptr,size_t line_skip,size_t n,unsigned weight)137 static void add_col_gray(unsigned *my_restrict col_buf, unsigned char *my_restrict ptr, size_t line_skip, size_t n, unsigned weight)
138 {
139 for (;n;n--) {
140 *col_buf+=weight*(*ptr);
141 ptr+=line_skip;
142 col_buf++;
143 }
144 }
145
146 /* We assume unsigned short holds at least 16 bits. */
add_row_gray(unsigned * my_restrict row_buf,unsigned char * my_restrict ptr,size_t n,unsigned weight)147 static void add_row_gray(unsigned *my_restrict row_buf, unsigned char *my_restrict ptr, size_t n, unsigned weight)
148 {
149 for (;n;n--) {
150 *row_buf+=weight**ptr;
151 ptr++;
152 row_buf++;
153 }
154 }
155
156 /* line_skip is in pixels. The column contains the whole pixels (R G B)
157 * We assume unsigned short holds at least 16 bits. */
158 #if defined(__ICC) && defined(USE_FP_SCALE)
159 /* ICC misoptimizes this function when inlining it */
160 ATTR_NOINLINE
161 #endif
add_col_color(scale_t * my_restrict col_buf,volatile unsigned short * my_restrict ptr,size_t line_skip,size_t n,ulonglong weight)162 static void add_col_color(scale_t *my_restrict col_buf,
163 #if defined(__GNUC__) && __GNUC__ == 3
164 volatile
165 #endif
166 unsigned short *my_restrict ptr,
167 size_t line_skip, size_t n, ulonglong weight)
168 {
169 if (!weight) return;
170 #ifndef USE_FP_SCALE
171 if (weight < 0x10000) {
172 unsigned short weight_16 = (unsigned short)weight;
173 for (;n;n--) {
174 col_buf[0]+=(scale_t)((unsigned)weight_16*(unsigned)ptr[0]);
175 col_buf[1]+=(scale_t)((unsigned)weight_16*(unsigned)ptr[1]);
176 col_buf[2]+=(scale_t)((unsigned)weight_16*(unsigned)ptr[2]);
177 ptr+=line_skip;
178 col_buf+=3;
179 }
180 } else
181 #endif
182 {
183 scale_t w = (scale_t)(longlong)weight;
184 for (;n;n--) {
185 col_buf[0]+=w*ptr[0];
186 col_buf[1]+=w*ptr[1];
187 col_buf[2]+=w*ptr[2];
188 ptr+=line_skip;
189 col_buf+=3;
190 }
191 }
192 }
193
194 /* n is in pixels. pixel is 3 unsigned shorts in series */
195 /* We assume unsigned short holds at least 16 bits. */
add_row_color(scale_t * my_restrict row_buf,volatile unsigned short * my_restrict ptr,size_t n,ulonglong weight)196 static void add_row_color(scale_t *my_restrict row_buf,
197 #if defined(__GNUC__) && __GNUC__ == 3
198 volatile
199 #endif
200 unsigned short *my_restrict ptr,
201 size_t n, ulonglong weight)
202 {
203 if (!weight) return;
204 #ifndef USE_FP_SCALE
205 if (weight < 0x10000) {
206 unsigned short weight_16 = (unsigned short)weight;
207 for (;n;n--) {
208 row_buf[0]+=(scale_t)((unsigned)weight_16*(unsigned)ptr[0]);
209 row_buf[1]+=(scale_t)((unsigned)weight_16*(unsigned)ptr[1]);
210 row_buf[2]+=(scale_t)((unsigned)weight_16*(unsigned)ptr[2]);
211 ptr+=3;
212 row_buf+=3;
213 }
214 } else
215 #endif
216 {
217 scale_t w = (scale_t)(longlong)weight;
218 for (;n;n--) {
219 row_buf[0]+=w*ptr[0];
220 row_buf[1]+=w*ptr[1];
221 row_buf[2]+=w*ptr[2];
222 ptr+=3;
223 row_buf+=3;
224 }
225 }
226 }
227
228 /* We assume unsigned holds at least 32 bits */
emit_and_bias_col_gray(unsigned * my_restrict col_buf,unsigned char * my_restrict out,size_t line_skip,size_t n,unsigned weight)229 static void emit_and_bias_col_gray(unsigned *my_restrict col_buf, unsigned char *my_restrict out,
230 size_t line_skip, size_t n, unsigned weight)
231 {
232 unsigned half=weight>>1;
233
234 for (;n;n--) {
235 *out=*col_buf/weight;
236 out+=line_skip;
237 *col_buf++=half;
238 }
239 }
240
241 /* We assume unsigned holds at least 32 bits */
emit_and_bias_row_gray(unsigned * my_restrict row_buf,unsigned char * my_restrict out,size_t n,unsigned weight)242 static void emit_and_bias_row_gray(unsigned *my_restrict row_buf, unsigned char *my_restrict out,
243 size_t n, unsigned weight)
244 {
245 unsigned half=weight>>1;
246
247 for (;n;n--) {
248 *out++=*row_buf/weight;
249 *row_buf++=half;
250 }
251 }
252
253 /* We assume unsigned holds at least 32 bits */
bias_buf_gray(unsigned * my_restrict col_buf,size_t n,unsigned half)254 static void bias_buf_gray(unsigned *my_restrict col_buf, size_t n, unsigned half)
255 {
256 for (;n;n--) *col_buf++=half;
257 }
258
259 /* We assume unsigned holds at least 32 bits */
bias_buf_color(scale_t * my_restrict col_buf,size_t n,scale_t half)260 static void bias_buf_color(scale_t *my_restrict col_buf, size_t n, scale_t half)
261 {
262 for (;n;n--) {
263 col_buf[0]=half;
264 col_buf[1]=half;
265 col_buf[2]=half;
266 col_buf+=3;
267 }
268 /* System activated */
269 }
270
271 #ifdef USE_FP_SCALE
272 #define op(x) ((x) * inv_weight)
273 #else
274 #define op(x) (sizeof(unsigned long) < sizeof(scale_t) && (x) == (unsigned long)(x) ? (unsigned long)(x) / weight : (x) / weight)
275 #endif
276
277 /* line skip is in pixels. Pixel is 3*unsigned short */
278 /* We assume unsigned holds at least 32 bits */
279 /* We assume unsigned short holds at least 16 bits. */
emit_and_bias_col_color(scale_t * my_restrict col_buf,unsigned short * my_restrict out,size_t line_skip,size_t n,unsigned weight)280 static void emit_and_bias_col_color(scale_t *my_restrict col_buf,
281 unsigned short *my_restrict out, size_t line_skip, size_t n, unsigned weight)
282 {
283 scale_t half=(scale_t)weight / 2;
284 #ifdef USE_FP_SCALE
285 scale_t inv_weight = (scale_t)1 / weight;
286 #endif
287 for (;n;n--) {
288 out[0]=(unsigned short)op(col_buf[0]);
289 col_buf[0]=half;
290 out[1]=(unsigned short)op(col_buf[1]);
291 col_buf[1]=half;
292 /* The following line is an enemy of the State and will be
293 * prosecuted according to the Constitution of The United States
294 * Cap. 20/3 ix. Sel. Bill 12/1920
295 * Moses 12/20 Erizea farizea 2:2:1:14
296 */
297 out[2]=(unsigned short)op(col_buf[2]);
298 col_buf[2]=half;
299 out+=line_skip;
300 col_buf+=3;
301 }
302 }
303
304 /* n is in pixels. pixel is 3 unsigned shorts in series. */
305 /* We assume unsigned holds at least 32 bits */
306 /* We assume unsigned short holds at least 16 bits. */
emit_and_bias_row_color(scale_t * my_restrict row_buf,unsigned short * my_restrict out,size_t n,unsigned weight)307 static void emit_and_bias_row_color(scale_t *my_restrict row_buf,
308 unsigned short *my_restrict out, size_t n, unsigned weight)
309 {
310 scale_t half=(scale_t)weight / 2;
311 #ifdef USE_FP_SCALE
312 scale_t inv_weight = (scale_t)1 / weight;
313 #endif
314 for (;n;n--) {
315 out[0]=(unsigned short)op(row_buf[0]);
316 row_buf[0]=half;
317 out[1]=(unsigned short)op(row_buf[1]);
318 row_buf[1]=half;
319 out[2]=(unsigned short)op(row_buf[2]);
320 row_buf[2]=half;
321 out+=3;
322 row_buf+=3;
323 }
324 }
325
326 #undef op
327
328 /* For enlargement only -- does linear filtering.
329 * Allocates output and frees input.
330 * We assume unsigned holds at least 32 bits */
enlarge_gray_horizontal(unsigned char * in,size_t ix,size_t y,unsigned char ** out,size_t ox)331 static void enlarge_gray_horizontal(unsigned char *in, size_t ix, size_t y, unsigned char **out, size_t ox)
332 {
333 unsigned *col_buf;
334 size_t total;
335 size_t out_pos,in_pos,in_begin,in_end;
336 unsigned half = (unsigned)((ox - 1) >> 1);
337 unsigned char *outptr;
338 unsigned char *inptr;
339
340 if (ox && ox * y / ox != y) overalloc();
341 if (ox * y > MAX_SIZE_T) overalloc();
342 outptr=mem_alloc(ox * y);
343 inptr=in;
344 *out=outptr;
345 if (ix==1) {
346 /* Dull copying */
347 for (;y;y--) {
348 memset(outptr,*inptr,ox);
349 outptr+=ox;
350 inptr++;
351 }
352 mem_free(in);
353 }else{
354 total=(ix-1)*(ox-1);
355 if (y > MAX_SIZE_T / sizeof(*col_buf)) overalloc();
356 col_buf=mem_alloc(y * sizeof(*col_buf));
357 bias_buf_gray(col_buf, y, half);
358 out_pos=0;
359 in_pos=0;
360 again:
361 in_begin=in_pos;
362 in_end=in_pos+ox-1;
363 add_col_gray(col_buf, inptr, ix, y, (unsigned)(in_end - out_pos));
364 add_col_gray(col_buf, inptr + 1, ix, y, (unsigned)(out_pos - in_begin));
365 emit_and_bias_col_gray(col_buf, outptr, ox, y, (unsigned)(ox - 1));
366 outptr++;
367 out_pos+=ix-1;
368 if (out_pos>in_end) {
369 in_pos=in_end;
370 inptr++;
371 }
372 if (out_pos>total) {
373 mem_free(in);
374 mem_free(col_buf);
375 return;
376 }
377 goto again;
378 }
379 /* Rohan, oh Rohan... */
380 /* ztracena zeme :) */
381 }
382
multiply_int(size_t a,size_t b)383 static inline longlong multiply_int(size_t a, size_t b)
384 {
385 #ifndef HAVE_LONG_LONG
386 volatile
387 #endif
388 longlong result = (ulonglong)a * (ulonglong)b;
389 #if !defined(__TINYC__) && !defined(HAVE_LONG_LONG)
390 if (result / a != (longlong)b) {
391 /*fprintf(stderr, "%lld, %lld, %d, %d\n", result / a, result, a, b);*/
392 overflow();
393 }
394 #endif
395 #ifndef HAVE_LONG_LONG
396 if (result == result + 1 || result == result - 1)
397 overflow();
398 #endif
399 return result;
400 }
401
402 /* For enlargement only -- does linear filtering
403 * Frees input and allocates output.
404 * We assume unsigned holds at least 32 bits
405 */
enlarge_color_horizontal(unsigned short * in,size_t ix,size_t y,unsigned short ** outa,size_t ox)406 static void enlarge_color_horizontal(unsigned short *in, size_t ix, size_t y,
407 unsigned short **outa, size_t ox)
408 {
409 #ifdef HAVE_OPENMP
410 int use_omp;
411 #endif
412 int n_threads;
413 size_t alloc_size;
414 scale_t *col_buf;
415 size_t a;
416 size_t skip=3*ix;
417 size_t oskip=3*ox;
418 unsigned short *out;
419
420 if (!in) {
421 *outa = NULL;
422 return;
423 }
424
425 if (ix==ox) {
426 *outa=in;
427 return;
428 }
429 if (ox && ox * y / ox != y) overalloc();
430 if (ox * y > MAX_SIZE_T / 3 / sizeof(*out)) overalloc();
431 out = mem_alloc_mayfail(sizeof(*out) * 3 * ox * y);
432 *outa=out;
433 if (!out) {
434 mem_free(in);
435 return;
436 }
437 if (ix==1) {
438 unsigned short *inp = in;
439 for (;y;y--,inp+=3) for (a=ox;a;a--,out+=3) {
440 out[0]=inp[0];
441 out[1]=inp[1];
442 out[2]=inp[2];
443 }
444 mem_free(in);
445 return;
446 }
447 multiply_int(ix-1,ox-1);
448
449 n_threads = omp_start();
450 #ifdef HAVE_OPENMP
451 use_omp = !OPENMP_NONATOMIC & (n_threads > 1) & (ox >= 24);
452 if (!use_omp)
453 n_threads = 1;
454 #endif
455 if (y > (MAX_SIZE_T - SMP_ALIGN + 1) / 3 / sizeof(*col_buf)) overalloc();
456 alloc_size = y * 3 * sizeof(*col_buf);
457 alloc_size = (alloc_size + SMP_ALIGN - 1) & ~(SMP_ALIGN - 1);
458 if (alloc_size > MAX_SIZE_T / n_threads) overalloc();
459 col_buf = mem_alloc_mayfail(alloc_size * n_threads);
460 if (!col_buf) goto skip_omp;
461 #ifdef HAVE_OPENMP
462 #pragma omp parallel default(none) firstprivate(col_buf,alloc_size,in,out,ix,ox,y,skip,oskip) if (use_omp)
463 #endif
464 {
465 scale_t *thread_col_buf;
466 ssize_t out_idx;
467 thread_col_buf = (scale_t *)((char *)col_buf + alloc_size * omp_get_thread_num());
468 bias_buf_color(thread_col_buf, y, (scale_t)(ox - 1) / 2);
469 #ifdef HAVE_OPENMP
470 #pragma omp for nowait
471 #endif
472 for (out_idx = 0; out_idx <= (ssize_t)(ox - 1); out_idx++) {
473 ulonglong out_pos, in_pos, in_end;
474 size_t in_idx;
475 out_pos = (ulonglong)out_idx * (ix - 1);
476 if (out_idx)
477 in_idx = (out_pos - 1) / (ox - 1);
478 else
479 in_idx = 0;
480 in_pos = (ulonglong)in_idx * (ox - 1);
481 in_end = in_pos + (ox - 1);
482 add_col_color(thread_col_buf, in + in_idx * 3, skip, y,
483 in_end - out_pos);
484 add_col_color(thread_col_buf, in + (in_idx + 1) * 3, skip, y,
485 out_pos - in_pos);
486 emit_and_bias_col_color(thread_col_buf, out + out_idx * 3, oskip, y, (unsigned)(ox - 1));
487 }
488 }
489 skip_omp:
490 omp_end();
491
492 mem_free(in);
493 if (col_buf) mem_free(col_buf);
494 else {
495 mem_free(out);
496 *outa = NULL;
497 }
498 }
499
500 /* Works for both enlarging and diminishing. Linear resample, no low pass.
501 * Automatically mem_frees the "in" and allocates "out". */
502 /* We assume unsigned holds at least 32 bits */
scale_gray_horizontal(unsigned char * in,size_t ix,size_t y,unsigned char ** out,size_t ox)503 static void scale_gray_horizontal(unsigned char *in, size_t ix, size_t y, unsigned char **out, size_t ox)
504 {
505 unsigned *col_buf;
506 size_t total=ix * ox;
507 size_t out_pos, in_pos, in_begin, in_end, out_end;
508 unsigned char *outptr;
509 unsigned char *inptr;
510
511 if (ix<ox) {
512 enlarge_gray_horizontal(in,ix,y,out,ox);
513 return;
514 }else if (ix==ox) {
515 *out=in;
516 return;
517 }
518 if (ox && ox * y / ox != y) overalloc();
519 if (ox * y > MAX_SIZE_T) overalloc();
520 outptr=mem_alloc(ox*y);
521 inptr=in;
522 *out=outptr;
523 if (y > MAX_SIZE_T / sizeof(*col_buf)) overalloc();
524 col_buf = mem_alloc(y * sizeof(*col_buf));
525 bias_buf_gray(col_buf, y, (unsigned)(ix >> 1));
526 out_pos=0;
527 in_pos=0;
528 again:
529 in_begin=in_pos;
530 in_end=in_pos+ox;
531 out_end=out_pos+ix;
532 if (in_begin<out_pos)in_begin=out_pos;
533 if (in_end>out_end)in_end=out_end;
534 add_col_gray(col_buf, inptr, ix, y, (unsigned)(in_end - in_begin));
535 in_end=in_pos+ox;
536 if (out_end>=in_end) {
537 in_pos=in_end;
538 inptr++;
539 }
540 if (out_end<=in_end) {
541 emit_and_bias_col_gray(col_buf, outptr, ox, y, (unsigned)ix);
542 out_pos=out_pos+ix;
543 outptr++;
544 }
545 if (out_pos==total) {
546 mem_free(in);
547 mem_free(col_buf);
548 return;
549 }
550 goto again;
551 }
552
553 /* Works for both enlarging and diminishing. Linear resample, no low pass.
554 * Does only one color component.
555 * Frees ina and allocates outa.
556 * If ox*3<=ix, and display_optimize, performs optimization for LCD.
557 */
scale_color_horizontal(unsigned short * in,size_t ix,size_t y,unsigned short ** outa,size_t ox)558 static void scale_color_horizontal(unsigned short *in, size_t ix, size_t y, unsigned short **outa, size_t ox)
559 {
560 #ifdef HAVE_OPENMP
561 int use_omp;
562 #endif
563 int n_threads;
564 size_t alloc_size;
565 scale_t *col_buf;
566 size_t skip = 3 * ix;
567 size_t oskip = 3 * ox;
568 unsigned short *out;
569
570 if (!in) {
571 *outa = NULL;
572 return;
573 }
574
575 if (ix==ox) {
576 *outa=in;
577 return;
578 }
579 if (ix<ox) {
580 enlarge_color_horizontal(in,ix,y,outa,ox);
581 return;
582 }
583 multiply_int(ix,ox);
584 if (ox && ox * y / ox != y) overalloc();
585 if (ox * y > MAX_SIZE_T / 3 / sizeof(*out)) overalloc();
586 out = mem_alloc_mayfail(sizeof(*out) * 3 * ox * y);
587 *outa=out;
588 if (!out) {
589 mem_free(in);
590 return;
591 }
592
593 n_threads = omp_start();
594 #ifdef HAVE_OPENMP
595 use_omp = !OPENMP_NONATOMIC & (n_threads > 1) & (ox >= 24);
596 if (!use_omp)
597 n_threads = 1;
598 #endif
599 if (y > (MAX_SIZE_T - SMP_ALIGN + 1) / 3 / sizeof(*col_buf)) overalloc();
600 alloc_size = y * 3 * sizeof(*col_buf);
601 alloc_size = (alloc_size + SMP_ALIGN - 1) & ~(SMP_ALIGN - 1);
602 if (alloc_size > MAX_SIZE_T / n_threads) overalloc();
603 col_buf = mem_alloc_mayfail(alloc_size * n_threads);
604 if (!col_buf) goto skip_omp;
605 #ifdef HAVE_OPENMP
606 #pragma omp parallel default(none) firstprivate(col_buf,alloc_size,in,out,ix,ox,y,skip,oskip) if (use_omp)
607 #endif
608 {
609 scale_t *thread_col_buf;
610 ssize_t out_idx;
611 thread_col_buf = (scale_t *)((char *)col_buf + alloc_size * omp_get_thread_num());
612 bias_buf_color(thread_col_buf, y, (scale_t)ix / 2);
613 #ifdef HAVE_OPENMP
614 #pragma omp for nowait
615 #endif
616 for (out_idx = 0; out_idx < (ssize_t)ox; out_idx++) {
617 ulonglong out_pos, out_end, in_pos;
618 size_t in_idx;
619 out_pos = (ulonglong)out_idx * ix;
620 out_end = out_pos + ix;
621 in_idx = out_pos / ox;
622 in_pos = (ulonglong)in_idx * ox;
623 do {
624 ulonglong in_begin, in_end;
625 in_begin = in_pos;
626 in_end = in_pos + ox;
627 if (in_begin < out_pos) in_begin = out_pos;
628 if (in_end > out_end) in_end = out_end;
629 add_col_color(thread_col_buf, in + in_idx * 3, skip, y, in_end - in_begin);
630 in_idx++;
631 in_pos += ox;
632 } while (in_pos < out_end);
633 emit_and_bias_col_color(thread_col_buf, out + out_idx * 3, oskip, y, (unsigned)ix);
634 }
635 }
636 skip_omp:
637 omp_end();
638
639 mem_free(in);
640 if (col_buf) mem_free(col_buf);
641 else {
642 mem_free(out);
643 *outa = NULL;
644 }
645 }
646
647 /* For magnification only. Does linear filtering. */
648 /* We assume unsigned holds at least 32 bits */
enlarge_gray_vertical(unsigned char * in,size_t x,size_t iy,unsigned char ** out,size_t oy)649 static void enlarge_gray_vertical(unsigned char *in, size_t x, size_t iy, unsigned char **out, size_t oy)
650 {
651 unsigned *row_buf;
652 size_t total;
653 size_t out_pos,in_pos,in_begin,in_end;
654 unsigned half = (unsigned)((oy - 1) >> 1);
655 unsigned char *outptr;
656 unsigned char *inptr;
657
658 if (iy==1) {
659 if (x && x * oy / x != oy) overalloc();
660 if (x * oy > MAX_SIZE_T) overalloc();
661 outptr = mem_alloc(oy * x);
662 *out=outptr;
663 for(;oy;oy--,outptr+=x)
664 memcpy(outptr,in,x);
665 mem_free(in);
666 }
667 else if (iy==oy) {
668 *out=in;
669 }else{
670 if (x && x * oy / x != oy) overalloc();
671 if (x * oy > MAX_SIZE_T) overalloc();
672 outptr = mem_alloc(oy * x);
673 inptr=in;
674 *out=outptr;
675 total=(iy-1)*(oy-1);
676 if (x > MAX_SIZE_T / sizeof(*row_buf)) overalloc();
677 row_buf=mem_alloc(x * sizeof(*row_buf));
678 bias_buf_gray(row_buf, x, half);
679 out_pos=0;
680 in_pos=0;
681 again:
682 in_begin=in_pos;
683 in_end=in_pos+oy-1;
684 add_row_gray(row_buf, inptr, x, (unsigned)(in_end - out_pos));
685 add_row_gray(row_buf, inptr + x, x, (unsigned)(out_pos - in_begin));
686 emit_and_bias_row_gray(row_buf, outptr, x, (unsigned)(oy - 1));
687 outptr+=x;
688 out_pos+=iy-1;
689 if (out_pos>in_end) {
690 in_pos=in_end;
691 inptr+=x;
692 }
693 if (out_pos>total) {
694 mem_free(in);
695 mem_free(row_buf);
696 return;
697 }
698 goto again;
699 }
700 }
701
702 /* For magnification only. Does linear filtering */
703 /* We assume unsigned holds at least 32 bits */
enlarge_color_vertical(unsigned short * in,size_t x,size_t iy,unsigned short ** outa,size_t oy)704 static void enlarge_color_vertical(unsigned short *in, size_t x, size_t iy, unsigned short **outa, size_t oy)
705 {
706 #ifdef HAVE_OPENMP
707 int use_omp;
708 #endif
709 int n_threads;
710 size_t alloc_size;
711 scale_t *row_buf;
712 unsigned short *out;
713
714 if (!in) {
715 *outa = NULL;
716 return;
717 }
718
719 if (iy==oy) {
720 *outa=in;
721 return;
722 }
723 /* Rivendell */
724 if (x && x * oy / x != oy) overalloc();
725 if (x * oy > MAX_SIZE_T / 3 / sizeof(*out)) overalloc();
726 out = mem_alloc_mayfail(sizeof(*out) * 3 * oy * x);
727 *outa=out;
728 if (!out) {
729 mem_free(in);
730 return;
731 }
732 if (iy==1) {
733 for (;oy;oy--) {
734 memcpy(out,in,3*x*sizeof(*out));
735 out+=3*x;
736 }
737 mem_free(in);
738 return;
739 }
740 multiply_int(iy-1,oy-1);
741
742 n_threads = omp_start();
743 #ifdef HAVE_OPENMP
744 use_omp = (!OPENMP_NONATOMIC | !(x & 3)) & (n_threads > 1) & (oy >= 24);
745 if (!use_omp)
746 n_threads = 1;
747 #endif
748 if (x > (MAX_SIZE_T - SMP_ALIGN + 1) / 3 / sizeof(*row_buf)) overalloc();
749 alloc_size = x * 3 * sizeof(*row_buf);
750 alloc_size = (alloc_size + SMP_ALIGN - 1) & ~(SMP_ALIGN - 1);
751 if (alloc_size > MAX_SIZE_T / n_threads) overalloc();
752 row_buf = mem_alloc_mayfail(alloc_size * n_threads);
753 if (!row_buf) goto skip_omp;
754 #ifdef HAVE_OPENMP
755 #pragma omp parallel default(none) firstprivate(row_buf,alloc_size,in,out,x,iy,oy) if (use_omp)
756 #endif
757 {
758 scale_t *thread_row_buf;
759 ssize_t out_idx;
760 thread_row_buf = (scale_t *)((char *)row_buf + alloc_size * omp_get_thread_num());
761 bias_buf_color(thread_row_buf,x,(scale_t)(oy-1) / 2);
762 #ifdef HAVE_OPENMP
763 #pragma omp for nowait
764 #endif
765 for (out_idx = 0; out_idx <= (ssize_t)(oy - 1); out_idx++) {
766 ulonglong out_pos, in_pos, in_end;
767 size_t in_idx;
768 out_pos = (ulonglong)out_idx * (iy - 1);
769 if (out_idx)
770 in_idx = (out_pos - 1) / (oy - 1);
771 else
772 in_idx = 0;
773 in_pos = (ulonglong)in_idx * (oy - 1);
774 in_end = in_pos + oy - 1;
775 add_row_color(thread_row_buf, in + in_idx * 3 * x, x,
776 in_end - out_pos);
777 add_row_color(thread_row_buf, in + (in_idx + 1) * 3 * x, x,
778 out_pos - in_pos);
779 emit_and_bias_row_color(thread_row_buf, out + out_idx * 3 * x, x, (unsigned)(oy - 1));
780 }
781 }
782 skip_omp:
783 omp_end();
784
785 mem_free(in);
786 if (row_buf) mem_free(row_buf);
787 else {
788 mem_free(out);
789 *outa = NULL;
790 }
791 }
792
793 /* Both enlarges and diminishes. Linear filtering.
794 * Automatically allocates output and frees input.
795 * We assume unsigned holds at least 32 bits */
scale_gray_vertical(unsigned char * in,size_t x,size_t iy,unsigned char ** out,size_t oy)796 static void scale_gray_vertical(unsigned char *in, size_t x, size_t iy, unsigned char **out, size_t oy)
797 {
798 unsigned *row_buf;
799 size_t total=iy*oy;
800 size_t out_pos, in_pos, in_begin, in_end, out_end;
801 unsigned char *outptr;
802 unsigned char *inptr;
803
804 /* Snow White, Snow White... */
805 if (iy<oy) {
806 enlarge_gray_vertical(in,x,iy,out,oy);
807 return;
808 }
809 if (iy==oy) {
810 *out=in;
811 return;
812 }
813 if (x && x * oy / x != oy) overalloc();
814 if (x * oy > MAX_SIZE_T) overalloc();
815 outptr=mem_alloc(x*oy);
816 inptr=in;
817 *out=outptr;
818 if (x > MAX_SIZE_T / sizeof(*row_buf)) overalloc();
819 row_buf = mem_calloc(x * sizeof(*row_buf));
820 bias_buf_gray(row_buf, x, (unsigned)(iy >> 1));
821 out_pos=0;
822 in_pos=0;
823 again:
824 in_begin=in_pos;
825 in_end=in_pos+oy;
826 out_end=out_pos+iy;
827 if (in_begin<out_pos)in_begin=out_pos;
828 if (in_end>out_end)in_end=out_end;
829 add_row_gray(row_buf, inptr, x, (unsigned)(in_end - in_begin));
830 in_end=in_pos+oy;
831 if (out_end>=in_end) {
832 in_pos=in_end;
833 inptr+=x;
834 }
835 if (out_end<=in_end) {
836 emit_and_bias_row_gray(row_buf, outptr, x, (unsigned)iy);
837 out_pos=out_pos+iy;
838 outptr+=x;
839 }
840 if (out_pos==total) {
841 mem_free(in);
842 mem_free(row_buf);
843 return;
844 }
845 goto again;
846 }
847
848 /* Both enlarges and diminishes. Linear filtering. Sizes are
849 in pixels. Sizes are not in bytes. 1 pixel=3 unsigned shorts.
850 We assume unsigned short can hold at least 16 bits.
851 We assume unsigned holds at least 32 bits.
852 */
scale_color_vertical(unsigned short * in,size_t x,size_t iy,unsigned short ** outa,size_t oy)853 static void scale_color_vertical(unsigned short *in, size_t x, size_t iy, unsigned short **outa, size_t oy)
854 {
855 #ifdef HAVE_OPENMP
856 int use_omp;
857 #endif
858 int n_threads;
859 size_t alloc_size;
860 scale_t *row_buf;
861 unsigned short *out;
862
863 if (!in) {
864 *outa = NULL;
865 return;
866 }
867
868 if (iy==oy) {
869 *outa=in;
870 return;
871 }
872 if (iy<oy) {
873 enlarge_color_vertical(in,x,iy,outa,oy);
874 return;
875 }
876 multiply_int(iy,oy);
877 if (x && x * oy / x != oy) overalloc();
878 if (x * oy > MAX_SIZE_T / 3 / sizeof(*out)) overalloc();
879 out = mem_alloc_mayfail(sizeof(*out) * 3 * oy * x);
880 *outa=out;
881 if (!out) {
882 mem_free(in);
883 return;
884 }
885 n_threads = omp_start();
886 #ifdef HAVE_OPENMP
887 use_omp = (!OPENMP_NONATOMIC | !(x & 3)) & (n_threads > 1) & (oy >= 24);
888 if (!use_omp)
889 n_threads = 1;
890 #endif
891 if (x > (MAX_SIZE_T - SMP_ALIGN + 1) / 3 / sizeof(*row_buf)) overalloc();
892 alloc_size = x * 3 * sizeof(*row_buf);
893 alloc_size = (alloc_size + SMP_ALIGN - 1) & ~(SMP_ALIGN - 1);
894 if (alloc_size > MAX_SIZE_T / n_threads) overalloc();
895 row_buf = mem_alloc_mayfail(alloc_size * n_threads);
896 if (!row_buf) goto skip_omp;
897 #ifdef HAVE_OPENMP
898 #pragma omp parallel default(none) firstprivate(row_buf,alloc_size,in,out,x,iy,oy) if (use_omp)
899 #endif
900 {
901 scale_t *thread_row_buf;
902 ssize_t out_idx;
903 thread_row_buf = (scale_t *)((char *)row_buf + alloc_size * omp_get_thread_num());
904 bias_buf_color(thread_row_buf,x,(scale_t)iy / 2);
905 #ifdef HAVE_OPENMP
906 #pragma omp for nowait
907 #endif
908 for (out_idx = 0; out_idx < (ssize_t)oy; out_idx++) {
909 ulonglong out_pos, out_end, in_pos;
910 size_t in_idx;
911 out_pos = (ulonglong)out_idx * iy;
912 out_end = out_pos + iy;
913 in_idx = out_pos / oy;
914 in_pos = (ulonglong)in_idx * oy;
915 do {
916 ulonglong in_begin, in_end;
917 in_begin = in_pos;
918 in_end = in_pos + oy;
919 if (in_begin < out_pos) in_begin = out_pos;
920 if (in_end > out_end) in_end = out_end;
921 add_row_color(thread_row_buf, in + in_idx * 3 * x, x, in_end - in_begin);
922 in_idx++;
923 in_pos += oy;
924 } while (in_pos < out_end);
925 emit_and_bias_row_color(thread_row_buf, out + out_idx * 3 * x, x, (unsigned)iy);
926 }
927 }
928 skip_omp:
929 omp_end();
930
931 mem_free(in);
932 if (row_buf) mem_free(row_buf);
933 else {
934 mem_free(out);
935 *outa = NULL;
936 }
937 }
938
939
940 /* Scales grayscale 8-bit map. Both enlarges and diminishes. Uses either low
941 * pass or bilinear filtering. Automatically mem_frees the "in".
942 * Automatically allocates "out".
943 */
scale_gray(unsigned char * in,size_t ix,size_t iy,unsigned char ** out,size_t ox,size_t oy)944 static void scale_gray(unsigned char *in, size_t ix, size_t iy, unsigned char **out, size_t ox, size_t oy)
945 {
946 unsigned char *intermediate_buffer;
947
948 if (!ix||!iy) {
949 if (in) mem_free(in);
950 if (ox && ox * oy / ox != oy) overalloc();
951 if (ox * oy > MAX_SIZE_T) overalloc();
952 *out = mem_calloc(ox * oy);
953 return;
954 }
955 if (ix*oy<ox*iy) {
956 scale_gray_vertical(in,ix,iy,&intermediate_buffer,oy);
957 scale_gray_horizontal(intermediate_buffer,ix,oy,out,ox);
958 }else{
959 scale_gray_horizontal(in,ix,iy,&intermediate_buffer,ox);
960 scale_gray_vertical(intermediate_buffer,ox,iy,out,oy);
961 }
962 }
963
964 /* To be called only when global variable display_optimize is 1 or 2.
965 * Performs a decimation according to this variable. Data shrink to 1/3
966 * and x is the smaller width.
967 * There must be 9*x*y unsigned shorts of data.
968 * x must be >=1.
969 * Performs realloc onto the buffer after decimation to save memory.
970 */
decimate_3(unsigned short ** data0,size_t x,size_t y)971 static void decimate_3(unsigned short **data0, size_t x, size_t y)
972 {
973 unsigned short *data=*data0;
974 unsigned short *ahead=data;
975 size_t i, futuresize;
976 if (!data)
977 return;
978 if (x && (size_t)x * (size_t)y / (size_t)x != (size_t)y) overalloc();
979 if ((size_t)x * (size_t)y > MAX_SIZE_T / 3 / sizeof(**data0)) overalloc();
980 futuresize = x * y * 3 * sizeof(**data0);
981
982 #ifdef DEBUG
983 if (!(x>0&&y>0)) internal_error("zero width or height in decimate_3");
984 #endif /* #Ifdef DEBUG */
985 if (display_optimize==1) {
986 if (x==1) {
987 for (;y;y--,ahead+=9,data+=3) {
988 data[0]=(ahead[0]+ahead[0]+ahead[3])/3;
989 data[1]=(ahead[1]+ahead[4]+ahead[7])/3;
990 data[2]=(ahead[5]+ahead[8]+ahead[8])/3;
991 }
992 }else{
993 for (;y;y--) {
994 data[0]=(ahead[0]+ahead[0]+ahead[3])/3;
995 data[1]=(ahead[1]+ahead[4]+ahead[7])/3;
996 data[2]=(ahead[5]+ahead[8]+ahead[11])/3;
997 for (ahead+=9,data+=3,i=x-2;i;i--,ahead+=9,data+=3) {
998 data[0]=(ahead[-3]+ahead[0]+ahead[3])/3;
999 data[1]=(ahead[1]+ahead[4]+ahead[7])/3;
1000 data[2]=(ahead[5]+ahead[8]+ahead[11])/3;
1001 }
1002 data[0]=(ahead[-3]+ahead[0]+ahead[3])/3;
1003 data[1]=(ahead[1]+ahead[4]+ahead[7])/3;
1004 data[2]=(ahead[5]+ahead[8]+ahead[8])/3;
1005 ahead+=9,data+=3;
1006 }
1007 }
1008 }else{
1009 /* display_optimize==2 */
1010 if (x==1) {
1011 for (;y;y--,ahead+=9,data+=3) {
1012 data[0]=(ahead[3]+ahead[6]+ahead[6])/3;
1013 data[1]=(ahead[1]+ahead[4]+ahead[7])/3;
1014 data[2]=(ahead[2]+ahead[2]+ahead[5])/3;
1015 }
1016 }else{
1017 for (;y;y--) {
1018 data[0]=(ahead[3]+ahead[6]+ahead[9])/3;
1019 data[1]=(ahead[1]+ahead[4]+ahead[7])/3;
1020 data[2]=(ahead[2]+ahead[2]+ahead[5])/3;
1021 for (ahead+=9,data+=3,i=x-2;i;i--,ahead+=9,data+=3) {
1022 data[0]=(ahead[3]+ahead[6]+ahead[9])/3;
1023 data[1]=(ahead[1]+ahead[4]+ahead[7])/3;
1024 data[2]=(ahead[-1]+ahead[2]+ahead[5])/3;
1025 }
1026 data[0]=(ahead[3]+ahead[6]+ahead[6])/3;
1027 data[1]=(ahead[1]+ahead[4]+ahead[7])/3;
1028 data[2]=(ahead[-1]+ahead[2]+ahead[5])/3;
1029 ahead+=9,data+=3;
1030 }
1031 }
1032 }
1033 *data0=mem_realloc(*data0,futuresize);
1034 }
1035
1036 /* Scales color 48-bits-per-pixel bitmap. Both enlarges and diminishes. Uses
1037 * either low pass or bilinear filtering. The memory organization for both
1038 * input and output are red, green, blue. All three of them are unsigned shorts 0-65535.
1039 * Allocates output and frees input
1040 * We assume unsigned short holds at least 16 bits.
1041 */
scale_color(unsigned short * in,size_t ix,size_t iy,unsigned short ** out,size_t ox,size_t oy)1042 void scale_color(unsigned short *in, size_t ix, size_t iy, unsigned short **out, size_t ox, size_t oy)
1043 {
1044 unsigned short *intermediate_buffer;
1045 int do_optimize;
1046 size_t ox0 = ox;
1047
1048 if (!ix||!iy) {
1049 if (in) mem_free(in);
1050 if (ox && ox * oy / ox != oy) overalloc();
1051 if (ox * oy > MAX_SIZE_T / 3 / sizeof(**out)) overalloc();
1052 *out = mem_calloc_mayfail(ox * oy * sizeof(**out) * 3);
1053 return;
1054 }
1055 if (display_optimize&&ox*3<=ix) {
1056 do_optimize=1;
1057 ox0=ox;
1058 ox*=3;
1059 }else do_optimize=0;
1060 if (ix*oy<ox*iy) {
1061 scale_color_vertical(in,ix,iy,&intermediate_buffer,oy);
1062 scale_color_horizontal(intermediate_buffer,ix,oy,out,ox);
1063 }else{
1064 scale_color_horizontal(in,ix,iy,&intermediate_buffer,ox);
1065 scale_color_vertical(intermediate_buffer,ox,iy,out,oy);
1066 }
1067 if (do_optimize) decimate_3(out, ox0, oy);
1068 }
1069
1070 /* Fills a block with given color. length is number of pixels. pixel is a
1071 * tribyte. 24 bits per pixel.
1072 */
mix_one_color_24(unsigned char * my_restrict dest,size_t length,unsigned char r,unsigned char g,unsigned char b)1073 void mix_one_color_24(unsigned char *my_restrict dest, size_t length, unsigned char r, unsigned char g, unsigned char b)
1074 {
1075 for (;length;length--) {
1076 dest[0]=r;
1077 dest[1]=g;
1078 dest[2]=b;
1079 dest+=3;
1080 }
1081 }
1082
1083 /* Fills a block with given color. length is number of pixels. pixel is a
1084 * tribyte. 48 bits per pixel.
1085 * We assume unsigned short holds at least 16 bits.
1086 */
mix_one_color_48(unsigned short * my_restrict dest,size_t length,unsigned short r,unsigned short g,unsigned short b)1087 void mix_one_color_48(unsigned short *my_restrict dest, size_t length, unsigned short r, unsigned short g, unsigned short b)
1088 {
1089 for (;length;length--) {
1090 dest[0]=r;
1091 dest[1]=g;
1092 dest[2]=b;
1093 dest+=3;
1094 }
1095 }
1096
1097 /* Mixes ink and paper of a letter, using alpha as alpha mask.
1098 * Only mixing in photon space makes physical sense so that the input values
1099 * must always be equivalent to photons and not to electrons!
1100 * length is number of pixels. pixel is a tribyte
1101 * alpha is 8-bit, rgb are all 16-bit
1102 * We assume unsigned short holds at least 16 bits.
1103 */
mix_two_colors(unsigned short * my_restrict dest,unsigned char * my_restrict alpha,size_t length,unsigned short r0,unsigned short g0,unsigned short b0,unsigned short r255,unsigned short g255,unsigned short b255)1104 static void mix_two_colors(unsigned short *my_restrict dest, unsigned char *my_restrict alpha,
1105 size_t length, unsigned short r0, unsigned short g0, unsigned short b0,
1106 unsigned short r255, unsigned short g255, unsigned short b255)
1107 {
1108 unsigned char mask, cmask;
1109
1110 for (;length;length--) {
1111 mask=*alpha++;
1112 if (((mask+1)&255)>=2) {
1113 cmask=255-mask;
1114 dest[0]=(mask*r255+cmask*r0+127)/255;
1115 dest[1]=(mask*g255+cmask*g0+127)/255;
1116 dest[2]=(mask*b255+cmask*b0+127)/255;
1117 }else{
1118 if (mask) {
1119 dest[0]=r255;
1120 dest[1]=g255;
1121 dest[2]=b255;
1122 }else{
1123 dest[0]=r0;
1124 dest[1]=g0;
1125 dest[2]=b0;
1126 }
1127 }
1128 dest+=3;
1129 }
1130 }
1131
1132 /* We assume unsigned short holds at least 16 bits. */
agx_and_uc_32_to_48_table(unsigned short * my_restrict dest,const unsigned char * my_restrict src,size_t length,unsigned short * my_restrict table,unsigned short rb,unsigned short gb,unsigned short bb)1133 void agx_and_uc_32_to_48_table(unsigned short *my_restrict dest,
1134 const unsigned char *my_restrict src, size_t length,
1135 unsigned short *my_restrict table,
1136 unsigned short rb, unsigned short gb, unsigned short bb)
1137 {
1138 unsigned char alpha, calpha;
1139 unsigned short ri, gi, bi;
1140
1141 for (;length;length--)
1142 {
1143 ri=table[src[0]];
1144 gi=table[src[1]+256];
1145 bi=table[src[2]+512];
1146 alpha=src[3];
1147 src+=4;
1148 if (((alpha+1)&255)>=2) {
1149 calpha=255-alpha;
1150 dest[0]=(ri*alpha+calpha*rb+127)/255;
1151 dest[1]=(gi*alpha+calpha*gb+127)/255;
1152 dest[2]=(bi*alpha+calpha*bb+127)/255;
1153 } else {
1154 if (alpha) {
1155 dest[0]=ri;
1156 dest[1]=gi;
1157 dest[2]=bi;
1158 } else {
1159 dest[0]=rb;
1160 dest[1]=gb;
1161 dest[2]=bb;
1162 }
1163 }
1164 dest+=3;
1165 }
1166 }
1167
1168 /* src is a block of four-bytes RGBA. All bytes are gamma corrected. length is
1169 * number of pixels. output is input powered to the given gamma, passed into
1170 * dest. src and dest may be identical and it will work. rb, gb, bb are 0-65535
1171 * in linear monitor output photon space
1172 */
1173 /* We assume unsigned short holds at least 16 bits. */
agx_and_uc_32_to_48(unsigned short * my_restrict dest,const unsigned char * my_restrict src,size_t length,float red_gamma,float green_gamma,float blue_gamma,unsigned short rb,unsigned short gb,unsigned short bb)1174 void agx_and_uc_32_to_48(unsigned short *my_restrict dest,
1175 const unsigned char *my_restrict src, size_t length, float red_gamma,
1176 float green_gamma, float blue_gamma, unsigned short rb,
1177 unsigned short gb, unsigned short bb)
1178 {
1179 float_double r,g,b;
1180 unsigned char alpha, calpha;
1181 unsigned short ri,gi,bi;
1182 const float_double inv_255=(float_double)(1/255.);
1183
1184 for (;length;length--)
1185 {
1186 r=src[0];
1187 g=src[1];
1188 b=src[2];
1189 alpha=src[3];
1190 src+=4;
1191 r*=inv_255;
1192 g*=inv_255;
1193 b*=inv_255;
1194 r=fd_pow(r,red_gamma);
1195 g=fd_pow(g,green_gamma);
1196 b=fd_pow(b,blue_gamma);
1197 ri=(unsigned)((r*65535)+(float_double)0.5);
1198 gi=(unsigned)((g*65535)+(float_double)0.5);
1199 bi=(unsigned)((b*65535)+(float_double)0.5);
1200 cmd_limit_16(ri);
1201 cmd_limit_16(gi);
1202 cmd_limit_16(bi);
1203 if (((alpha+1)&255)>=2) {
1204 calpha=255-alpha;
1205 dest[0]=(unsigned short)((ri*alpha+calpha*rb+127U)/255U);
1206 dest[1]=(unsigned short)((gi*alpha+calpha*gb+127U)/255U);
1207 dest[2]=(unsigned short)((bi*alpha+calpha*bb+127U)/255U);
1208 }else{
1209 if (alpha) {
1210 dest[0]=ri;
1211 dest[1]=gi;
1212 dest[2]=bi;
1213 }else{
1214 dest[0]=rb;
1215 dest[1]=gb;
1216 dest[2]=bb;
1217 }
1218 }
1219 dest+=3;
1220 }
1221 }
1222 /* src is a block of four-bytes RGBA. All bytes are gamma corrected. length is
1223 * number of pixels. output is input powered to the given gamma, passed into
1224 * dest. src and dest may be identical and it will work. rb, gb, bb are 0-65535
1225 * in linear monitor output photon space. alpha 255 means full image no background.
1226 */
1227 /* We assume unsigned short holds at least 16 bits. */
agx_and_uc_64_to_48(unsigned short * my_restrict dest,const unsigned short * my_restrict src,size_t length,float red_gamma,float green_gamma,float blue_gamma,unsigned short rb,unsigned short gb,unsigned short bb)1228 void agx_and_uc_64_to_48(unsigned short *my_restrict dest,
1229 const unsigned short *my_restrict src, size_t length, float red_gamma,
1230 float green_gamma, float blue_gamma, unsigned short rb,
1231 unsigned short gb, unsigned short bb)
1232 {
1233 float_double r,g,b;
1234 unsigned short alpha, calpha;
1235 unsigned short ri,gi,bi;
1236 const float_double inv_65535=(float_double)(1/65535.);
1237
1238 for (;length;length--)
1239 {
1240 r=src[0];
1241 g=src[1];
1242 b=src[2];
1243 alpha=src[3];
1244 src+=4;
1245 r*=inv_65535;
1246 g*=inv_65535;
1247 b*=inv_65535;
1248 r=fd_pow(r,red_gamma);
1249 g=fd_pow(g,green_gamma);
1250 b=fd_pow(b,blue_gamma);
1251 ri=(unsigned short)(r*65535+(float_double)0.5);
1252 gi=(unsigned short)(g*65535+(float_double)0.5);
1253 bi=(unsigned short)(b*65535+(float_double)0.5);
1254 cmd_limit_16(ri);
1255 cmd_limit_16(gi);
1256 cmd_limit_16(bi);
1257 if (((alpha+1)&65535)>=2) {
1258 calpha=65535-alpha;
1259 dest[0]=(unsigned short)((ri*(unsigned)alpha+(unsigned)calpha*rb+32767U)/65535U);
1260 dest[1]=(unsigned short)((gi*(unsigned)alpha+(unsigned)calpha*gb+32767U)/65535U);
1261 dest[2]=(unsigned short)((bi*(unsigned)alpha+(unsigned)calpha*bb+32767U)/65535U);
1262 }else{
1263 if (alpha) {
1264 dest[0]=ri;
1265 dest[1]=gi;
1266 dest[2]=bi;
1267 }else{
1268 dest[0]=rb;
1269 dest[1]=gb;
1270 dest[2]=bb;
1271 }
1272 }
1273 dest+=3;
1274 }
1275 }
1276
1277 /* src is a block of four-bytes RGBA. All bytes are gamma corrected. length is
1278 * number of pixels. output is input powered to the given gamma, passed into
1279 * dest. src and dest may be identical and it will work. rb, gb, bb are 0-65535
1280 * in linear monitor output photon space. alpha 255 means full image no background.
1281 * We assume unsigned short holds at least 16 bits. */
agx_and_uc_64_to_48_table(unsigned short * my_restrict dest,const unsigned short * my_restrict src,size_t length,unsigned short * my_restrict gamma_table,unsigned short rb,unsigned short gb,unsigned short bb)1282 void agx_and_uc_64_to_48_table(unsigned short *my_restrict dest,
1283 const unsigned short *my_restrict src, size_t length, unsigned short *my_restrict gamma_table,
1284 unsigned short rb, unsigned short gb, unsigned short bb)
1285 {
1286 unsigned short alpha, calpha;
1287 unsigned short ri,gi,bi;
1288
1289 for (;length;length--)
1290 {
1291 ri=gamma_table[*src];
1292 gi=gamma_table[src[1]+65536];
1293 bi=gamma_table[src[2]+131072];
1294 alpha=src[3];
1295 src+=4;
1296 if (((alpha+1)&65535)>=2) {
1297 calpha=65535-alpha;
1298 dest[0]=(ri*alpha+calpha*rb+32767)/65535;
1299 dest[1]=(gi*alpha+calpha*gb+32767)/65535;
1300 dest[2]=(bi*alpha+calpha*bb+32767)/65535;
1301 }else{
1302 if (alpha) {
1303 dest[0]=ri;
1304 dest[1]=gi;
1305 dest[2]=bi;
1306 }else{
1307 dest[0]=rb;
1308 dest[1]=gb;
1309 dest[2]=bb;
1310 }
1311 }
1312 dest+=3;
1313 }
1314 }
1315
1316 /* src is a block of three-bytes. All bytes are gamma corrected. length is
1317 * number of triplets. output is input powered to the given gamma, passed into
1318 * dest. src and dest may be identical and it will work.
1319 * We assume unsigned short holds at least 16 bits. */
agx_48_to_48(unsigned short * my_restrict dest,const unsigned short * my_restrict src,size_t length,float red_gamma,float green_gamma,float blue_gamma)1320 void agx_48_to_48(unsigned short *my_restrict dest,
1321 const unsigned short *my_restrict src, size_t length, float red_gamma,
1322 float green_gamma, float blue_gamma)
1323 {
1324 float_double a;
1325 const float_double inv_65535=(float_double)(1/65535.);
1326
1327 for (;length;length--,src+=3,dest+=3)
1328 {
1329 a=src[0];
1330 a*=inv_65535;
1331 a=fd_pow(a,red_gamma);
1332 dest[0]=(unsigned short)((a*65535)+(float_double)0.5);
1333 cmd_limit_16(dest[0]);
1334 a=src[1];
1335 a*=inv_65535;
1336 a=fd_pow(a,green_gamma);
1337 dest[1]=(unsigned short)((a*65535)+(float_double)0.5);
1338 cmd_limit_16(dest[1]);
1339 a=src[2];
1340 a*=inv_65535;
1341 a=fd_pow(a,blue_gamma);
1342 dest[2]=(unsigned short)((a*65535)+(float_double)0.5);
1343 cmd_limit_16(dest[2]);
1344 }
1345 }
1346
1347 /* src is a block of three-bytes. All bytes are gamma corrected. length is
1348 * number of triples. output is input powered to the given gamma, passed into
1349 * dest. src and dest may be identical and it will work.
1350 * We assume unsigned short holds at least 16 bits. */
agx_48_to_48_table(unsigned short * my_restrict dest,const unsigned short * my_restrict src,size_t length,unsigned short * my_restrict table)1351 void agx_48_to_48_table(unsigned short *my_restrict dest,
1352 const unsigned short *my_restrict src, size_t length, unsigned short *my_restrict table)
1353 {
1354 for (;length;length--,src+=3,dest+=3)
1355 {
1356 dest[0]=table[*src];
1357 dest[1]=table[src[1]+65536];
1358 dest[2]=table[src[2]+131072];
1359 }
1360 }
1361
1362 /* src is a block of three-bytes. All bytes are gamma corrected. length is
1363 * number of triples. output is input powered to the given gamma, passed into
1364 * dest. src and dest may be identical and it will work.
1365 * We assume unsigned short holds at least 16 bits. */
agx_24_to_48(unsigned short * my_restrict dest,const unsigned char * my_restrict src,size_t length,float red_gamma,float green_gamma,float blue_gamma)1366 void agx_24_to_48(unsigned short *my_restrict dest, const unsigned char *my_restrict src,
1367 size_t length, float red_gamma, float green_gamma, float
1368 blue_gamma)
1369 {
1370 float_double a;
1371 const float_double inv_255=(float_double)(1/255.);
1372
1373 for (;length;length--,src+=3,dest+=3)
1374 {
1375 a=*src;
1376 a*=inv_255;
1377 a=fd_pow(a,red_gamma);
1378 dest[0]=(unsigned short)((a*65535)+(float_double)0.5);
1379 cmd_limit_16(dest[0]);
1380 a=src[1];
1381 a*=inv_255;
1382 a=fd_pow(a,green_gamma);
1383 dest[1]=(unsigned short)((a*65535)+(float_double)0.5);
1384 cmd_limit_16(dest[1]);
1385 a=src[2];
1386 a*=inv_255;
1387 a=fd_pow(a,blue_gamma);
1388 dest[2]=(unsigned short)((a*65535)+(float_double)0.5);
1389 cmd_limit_16(dest[2]);
1390 }
1391 }
1392
1393 /* Allocates new gamma_table and fills it with mapping 8 bits ->
1394 * power to user_gamma/cimg->*_gamma -> 16 bits
1395 * We assume unsigned short holds at least 16 bits. */
make_gamma_table(struct cached_image * cimg)1396 void make_gamma_table(struct cached_image *cimg)
1397 {
1398 float_double rg=(float_double)((float_double)(user_gamma tcc_hack) / cimg->red_gamma);
1399 float_double gg=(float_double)((float_double)(user_gamma tcc_hack) / cimg->green_gamma);
1400 float_double bg=(float_double)((float_double)(user_gamma tcc_hack) / cimg->blue_gamma);
1401 int a;
1402 unsigned short *ptr_16;
1403 unsigned short last_val;
1404 const float_double inv_255=(float_double)(1/255.);
1405 const float_double inv_65535=(float_double)(1/65535.);
1406
1407 if (cimg->buffer_bytes_per_pixel<=4) {
1408 /* 8-bit */
1409 ptr_16=mem_alloc(768*sizeof(*(cimg->gamma_table)));
1410 cimg->gamma_table=ptr_16;
1411 for (a=0;a<256;a++,ptr_16++) {
1412 last_val = (unsigned short)(65535*fd_pow((float_double)a*inv_255,rg)+(float_double)0.5);
1413 cmd_limit_16(last_val);
1414 *ptr_16 = last_val;
1415 }
1416 for (a=0;a<256;a++,ptr_16++) {
1417 last_val = (unsigned short)(65535*fd_pow((float_double)a*inv_255,gg)+(float_double)0.5);
1418 cmd_limit_16(last_val);
1419 *ptr_16 = last_val;
1420 }
1421 for (a=0;a<256;a++,ptr_16++) {
1422 last_val = (unsigned short)(65535*fd_pow((float_double)a*inv_255,bg)+(float_double)0.5);
1423 cmd_limit_16(last_val);
1424 *ptr_16 = last_val;
1425 }
1426 }else{
1427 int x_slow_fpu;
1428 if (gamma_bits != 2) x_slow_fpu = !gamma_bits;
1429 else x_slow_fpu = slow_fpu == 1;
1430
1431 last_val = 0; /* against warning */
1432
1433 /* 16-bit */
1434 ptr_16=mem_alloc(196608*sizeof(*(cimg->gamma_table)));
1435 cimg->gamma_table=ptr_16;
1436 for (a=0;a<0x10000;a++,ptr_16++) {
1437 if (!x_slow_fpu || !(a & 0xff)) {
1438 last_val = (unsigned short)(65535*fd_pow((float_double)a*inv_65535,rg)+(float_double)0.5);
1439 cmd_limit_16(last_val);
1440 }
1441 *ptr_16 = last_val;
1442 }
1443 for (a=0;a<0x10000;a++,ptr_16++) {
1444 if (!x_slow_fpu || !(a & 0xff)) {
1445 last_val = (unsigned short)(65535*fd_pow((float_double)a*inv_65535,gg)+(float_double)0.5);
1446 cmd_limit_16(last_val);
1447 }
1448 *ptr_16 = last_val;
1449 }
1450 for (a=0;a<0x10000;a++,ptr_16++) {
1451 if (!x_slow_fpu || !(a & 0xff)) {
1452 last_val = (unsigned short)(65535*fd_pow((float_double)a*inv_65535,bg)+(float_double)0.5);
1453 cmd_limit_16(last_val);
1454 }
1455 *ptr_16 = last_val;
1456 }
1457 }
1458 }
1459
1460 /* We assume unsigned short holds at least 16 bits. */
agx_24_to_48_table(unsigned short * my_restrict dest,const unsigned char * my_restrict src,size_t length,unsigned short * my_restrict table)1461 void agx_24_to_48_table(unsigned short *my_restrict dest, const unsigned char *my_restrict src,
1462 size_t length, unsigned short *my_restrict table)
1463 {
1464 for (;length;length--,src+=3,dest+=3)
1465 {
1466 dest[0]=table[src[0]];
1467 dest[1]=table[src[1]+256];
1468 dest[2]=table[src[2]+512];
1469 }
1470 }
1471
1472 #if 0
1473 /* Input is 0-255 (8-bit). Output is 0-255 (8-bit)*/
1474 unsigned char ags_8_to_8(unsigned char input, float gamma)
1475 {
1476 const float_double inv_255=1/255.;
1477 return 255*fd_pow((float_double)input*inv_255,gamma)+(float_double)0.5;
1478 }
1479 #endif
1480
1481 /* Input is 0-255 (8-bit). Output is 0-65535 (16-bit)*/
1482 /* We assume unsigned short holds at least 16 bits. */
ags_8_to_16(unsigned char input,float gamma)1483 unsigned short ags_8_to_16(unsigned char input, float gamma)
1484 {
1485 float_double a=input;
1486 unsigned short retval;
1487 const float_double inv_255=(float_double)(1/255.);
1488
1489 a*=inv_255;
1490 a=fd_pow(a,gamma);
1491 a*=65535;
1492 retval = (unsigned short)(a+(float_double)0.5);
1493 cmd_limit_16(retval);
1494 return retval;
1495 }
1496
1497 /* Input is 0-65535 (16-bit). Output is 0-255 (8-bit)*/
1498 /* We assume unsigned short holds at least 16 bits. */
ags_16_to_8(unsigned short input,float gamma)1499 unsigned char ags_16_to_8(unsigned short input, float gamma)
1500 {
1501 const float_double inv_65535=(float_double)(1/65535.);
1502 return (unsigned char)(fd_pow((float_double)input*inv_65535,gamma)*255+(float_double)0.5);
1503 }
1504
1505 /* Input is 0-65535 (16-bit). Output is 0-255 (8-bit)*/
ags_16_to_16(unsigned short input,float gamma)1506 unsigned short ags_16_to_16(unsigned short input, float gamma)
1507 {
1508 unsigned short retval;
1509 const float_double inv_65535=(float_double)(1/65535.);
1510
1511 retval = (unsigned short)(65535*fd_pow((float_double)input*inv_65535,gamma)+(float_double)0.5);
1512 cmd_limit_16(retval);
1513 return retval;
1514 }
1515
1516 #define FONT_NORMAL 1
1517 #define FONT_BOLD 2
1518 #define FONT_MONOSPACED 3
1519
1520 /* Returns a pointer to a structure describing the letter found or NULL
1521 * if the letter is not found. Tries all possibilities in the style table
1522 * before returning NULL.
1523 */
find_stored_letter(struct style * style,int letter_number)1524 static struct letter *find_stored_letter(struct style *style, int letter_number)
1525 {
1526 int tries[3];
1527 int try;
1528 if (style->flags & FF_MONOSPACED) {
1529 tries[0] = FONT_MONOSPACED;
1530 if (style->flags & FF_BOLD) {
1531 tries[1] = FONT_BOLD;
1532 tries[2] = FONT_NORMAL;
1533 } else {
1534 tries[1] = FONT_NORMAL;
1535 tries[2] = FONT_BOLD;
1536 }
1537 } else {
1538 if (style->flags & FF_BOLD) {
1539 tries[0] = FONT_BOLD;
1540 tries[1] = FONT_NORMAL;
1541 tries[2] = FONT_MONOSPACED;
1542 } else {
1543 tries[0] = FONT_NORMAL;
1544 tries[1] = FONT_MONOSPACED;
1545 tries[2] = FONT_BOLD;
1546 }
1547 }
1548 for (try = 0; try < 3; try++) {
1549 struct font *font = &font_table[tries[try]];
1550 int start = font->begin;
1551 int result;
1552 #define EQ(v, key) (letter_data[start + v].code == key)
1553 #define AB(v, key) (letter_data[start + v].code > key)
1554 BIN_SEARCH(font->length, EQ, AB, letter_number, result);
1555 if (result >= 0)
1556 return letter_data + start + result;
1557 }
1558 return letter_data + font_table[0].begin;
1559 }
1560
1561 struct read_work {
1562 const unsigned char *pointer;
1563 int length;
1564 };
1565
read_stored_data(png_structp png_ptr,png_bytep data,png_size_t length)1566 static void read_stored_data(png_structp png_ptr, png_bytep data, png_size_t length)
1567 {
1568 struct read_work *work;
1569
1570 length=(png_uint_32)length;
1571
1572 work=png_get_io_ptr(png_ptr);
1573 if (length>(png_uint_32)work->length) png_error(png_ptr,"Ran out of input data");
1574 memcpy(data,work->pointer,length);
1575 work->length-=(int)length;
1576 work->pointer+=length;
1577 }
1578
my_png_warning(png_structp a,png_const_charp b)1579 static void my_png_warning(png_structp a, png_const_charp b)
1580 {
1581 }
1582
1583 static jmp_buf png_error_jump;
1584 static int png_error_jump_valid = 0;
1585
my_png_error(png_structp a,png_const_charp error_string)1586 static void my_png_error(png_structp a, png_const_charp error_string)
1587 {
1588 if (png_error_jump_valid)
1589 longjmp(png_error_jump, 1);
1590 error("Error when loading compiled-in font: %s.", error_string);
1591 }
1592
1593 /* Loads width and height of the PNG (nothing is scaled). Style table is
1594 * already incremented.
1595 */
load_metric(struct style * style,int char_number,int * x,int * y)1596 static void load_metric(struct style *style, int char_number, int *x, int *y)
1597 {
1598 struct letter *l;
1599
1600 #ifdef HAVE_FREETYPE
1601 if (style->ft_face) {
1602 *y = style->height;
1603 if (!freetype_load_metric_cached(style, char_number, x, *y))
1604 return;
1605 }
1606 #endif
1607
1608 l = find_stored_letter(style, char_number);
1609 if (!l) {
1610 *x = 0;
1611 *y = 0;
1612 } else {
1613 *x = l->xsize;
1614 *y = l->ysize;
1615 }
1616 return;
1617 }
1618
1619 #ifdef PNG_USER_MEM_SUPPORTED
my_png_alloc(png_structp png_ptr,png_size_t size)1620 void *my_png_alloc(png_structp png_ptr, png_size_t size)
1621 {
1622 void *ptr = mem_alloc_mayfail(size);
1623 return ptr;
1624 }
my_png_free(png_structp png_ptr,void * ptr)1625 void my_png_free(png_structp png_ptr, void *ptr)
1626 {
1627 if (ptr) mem_free(ptr);
1628 }
1629 #endif
1630
dip_set_gamma(png_structp png_ptr,png_infop info_ptr)1631 static void dip_set_gamma(png_structp png_ptr, png_infop info_ptr)
1632 {
1633 png_error_jump_valid = 1;
1634 if (!setjmp(png_error_jump)) {
1635 double gamma;
1636 if (png_get_gAMA(png_ptr, info_ptr, &gamma))
1637 png_set_gamma(png_ptr, 1.0, gamma);
1638 else
1639 png_set_gamma(png_ptr, 1.0, sRGB_gamma);
1640 }
1641 png_error_jump_valid = 0;
1642 }
1643
1644 /* The data tha fall out of this function express this: 0 is paper. 255 is ink. 34
1645 * is 34/255ink+(255-34)paper. No gamma is involved in this formula, as you can see.
1646 * The multiplications and additions take place in photon space.
1647 */
load_char(unsigned char ** dest,int * x,int * y,const unsigned char * png_data,int png_length)1648 static void load_char(unsigned char **dest, int *x, int *y, const unsigned char *png_data, int png_length)
1649 {
1650 png_structp png_ptr;
1651 png_infop info_ptr;
1652 int y1,number_of_passes;
1653 unsigned char **ptrs;
1654 struct read_work work;
1655
1656 work.pointer = png_data;
1657 work.length = png_length;
1658
1659 retry1:
1660 #ifdef PNG_USER_MEM_SUPPORTED
1661 png_ptr = png_create_read_struct_2(PNG_LIBPNG_VER_STRING,
1662 NULL, my_png_error, my_png_warning,
1663 NULL, my_png_alloc, my_png_free);
1664 #else
1665 png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
1666 NULL, my_png_error, my_png_warning);
1667 #endif
1668 if (!png_ptr) {
1669 if (out_of_memory(0, NULL, 0)) goto retry1;
1670 fatal_exit("png_create_read_struct failed");
1671 }
1672 retry2:
1673 info_ptr = png_create_info_struct(png_ptr);
1674 if (!info_ptr) {
1675 if (out_of_memory(0, NULL, 0)) goto retry2;
1676 fatal_exit("png_create_info_struct failed");
1677 }
1678 png_set_read_fn(png_ptr, &work, (png_rw_ptr)read_stored_data);
1679 png_read_info(png_ptr, info_ptr);
1680 *x = (int)png_get_image_width(png_ptr, info_ptr);
1681 *y = (int)png_get_image_height(png_ptr, info_ptr);
1682 dip_set_gamma(png_ptr, info_ptr);
1683 {
1684 int bit_depth;
1685 int color_type;
1686
1687 color_type = png_get_color_type(png_ptr, info_ptr);
1688 bit_depth = png_get_bit_depth(png_ptr, info_ptr);
1689 if (color_type == PNG_COLOR_TYPE_GRAY) {
1690 if (bit_depth < 8) {
1691 png_set_expand(png_ptr);
1692 }
1693 if (bit_depth == 16) {
1694 png_set_strip_16(png_ptr);
1695 }
1696 }
1697 if (color_type == PNG_COLOR_TYPE_PALETTE) {
1698 png_set_expand(png_ptr);
1699 #ifdef HAVE_PNG_SET_RGB_TO_GRAY
1700 png_set_rgb_to_gray(png_ptr, 1, -1, -1);
1701 #else
1702 goto end;
1703 #endif
1704 }
1705 if (color_type & PNG_COLOR_MASK_ALPHA) {
1706 png_set_strip_alpha(png_ptr);
1707 }
1708 if (color_type == PNG_COLOR_TYPE_RGB ||
1709 color_type == PNG_COLOR_TYPE_RGB_ALPHA) {
1710 #ifdef HAVE_PNG_SET_RGB_TO_GRAY
1711 png_set_rgb_to_gray(png_ptr, 1, -1, -1);
1712 #else
1713 goto end;
1714 #endif
1715 }
1716 }
1717 /* If the depth is different from 8 bits/gray, make the libpng expand
1718 * it to 8 bit gray.
1719 */
1720 number_of_passes = png_set_interlace_handling(png_ptr);
1721 png_read_update_info(png_ptr, info_ptr);
1722 if (*x && (unsigned)*x * (unsigned)*y / (unsigned)*x != (unsigned)*y) overalloc();
1723 if ((unsigned)*x * (unsigned)*y > MAXINT) overalloc();
1724 *dest = mem_alloc(*x * *y);
1725 if ((unsigned)*y > MAXINT / sizeof(*ptrs)) overalloc();
1726 ptrs = mem_alloc(*y * sizeof(*ptrs));
1727 for (y1 = 0; y1 < *y; y1++) ptrs[y1] = *dest + *x * y1;
1728 for (;number_of_passes; number_of_passes--) {
1729 png_read_rows(png_ptr, ptrs, NULL, *y);
1730 }
1731 png_read_end(png_ptr, NULL);
1732 png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
1733 mem_free(ptrs);
1734 return;
1735 #ifndef HAVE_PNG_SET_RGB_TO_GRAY
1736 end:
1737 if (*x && (unsigned)*x * (unsigned)*y / (unsigned)*x != (unsigned)*y) overalloc();
1738 if ((unsigned)*x * (unsigned)*y > MAXINT) overalloc();
1739 *dest=mem_calloc(*x * *y));
1740 return;
1741 #endif
1742 }
1743
1744 /* Like load_char, but we dictate the y.
1745 */
load_scaled_char(unsigned char ** dest,int * x,int y,const unsigned char * png_data,int png_length,struct style * style)1746 static void load_scaled_char(unsigned char **dest, int *x, int y, const unsigned char *png_data, int png_length, struct style *style)
1747 {
1748 unsigned char *interm;
1749 unsigned char *interm2;
1750 unsigned char *i2ptr, *dptr;
1751 int ix, iy, y0, x0, c;
1752 float conv0, conv1, sharpness,contrast;
1753
1754 load_char(&interm, &ix, &iy, png_data, png_length);
1755 if (style->mono_space >= 0)
1756 *x = compute_width(style->mono_space, style->mono_height, y);
1757 else
1758 *x = compute_width(ix, iy, y);
1759 if (display_optimize) *x *= 3;
1760 scale_gray(interm, ix, iy, dest, *x, y);
1761 if (y > 32 || y <= 0) return; /* No convolution */
1762 ix = *x + 2; /* There is one-pixel border around */
1763 iy = y + 2;
1764 if (ix && (unsigned)ix * (unsigned)iy / (unsigned)ix != (unsigned)iy) overalloc();
1765 if ((unsigned)ix * (unsigned)iy > MAXINT) overalloc();
1766 interm2 = mem_alloc(ix * iy);
1767 i2ptr = interm2 + ix + 1;
1768 dptr = *dest;
1769 memset(interm2, 0, ix);
1770 memset(interm2 + (iy - 1) * ix, 0, ix);
1771 for (y0 = y; y0; y0--) {
1772 i2ptr[-1] = 0;
1773 memcpy(i2ptr, dptr, *x);
1774 i2ptr[*x] = 0;
1775 i2ptr += ix;
1776 dptr += *x;
1777 }
1778 i2ptr = interm2 + ix + 1;
1779 dptr = *dest;
1780
1781 /* Determine the sharpness and contrast */
1782 sharpness = fancy_constants[2 * y - 2];
1783 contrast = fancy_constants[2 * y - 1];
1784
1785 /* Compute the matrix constants from contrast and sharpness */
1786 conv0 = (1 + sharpness) * contrast;
1787 conv1 = (float)(-sharpness * (float)0.25 * contrast);
1788
1789 for (y0 = y; y0; y0--) {
1790 for (x0 = *x; x0; x0--) {
1791 /* Convolution */
1792 c=(int)((*i2ptr * conv0) + i2ptr[-ix] * conv1 + i2ptr[-1] * conv1 + i2ptr[1] * conv1 + i2ptr[ix] * conv1 + (float)0.5);
1793 if (c & ~255) c = c < 0 ? 0 : 255;
1794 *dptr = (unsigned char)c;
1795 dptr++;
1796 i2ptr++;
1797 }
1798 i2ptr += 2;
1799 }
1800 mem_free(interm2);
1801 }
1802
1803 static struct font_cache_entry *locked_color_entry = NULL;
1804
1805 /* Adds required entry into font_cache and returns pointer to the entry.
1806 */
supply_color_cache_entry(struct style * style,struct letter * letter,int char_number)1807 ATTR_NOINLINE static struct font_cache_entry *supply_color_cache_entry(struct style *style, struct letter *letter, int char_number)
1808 {
1809 int found_x, found_y;
1810 unsigned char *found_data;
1811 struct font_cache_entry *neww;
1812 unsigned short *primary_data;
1813 unsigned short red, green, blue;
1814 unsigned bytes_consumed;
1815
1816 found_y = style->height;
1817 #ifdef HAVE_FREETYPE
1818 if (!letter) {
1819 if (freetype_type_character(style, char_number, &found_data, &found_x, found_y))
1820 return NULL;
1821 } else
1822 #endif
1823 {
1824 load_scaled_char(&found_data, &found_x, found_y, letter->begin, letter->length, style);
1825 }
1826
1827 neww = mem_alloc(sizeof(struct font_cache_entry));
1828 locked_color_entry = neww;
1829 neww->bitmap.x = found_x;
1830 neww->bitmap.y = found_y;
1831 neww->r0 = style->r0;
1832 neww->g0 = style->g0;
1833 neww->b0 = style->b0;
1834 neww->r1 = style->r1;
1835 neww->g1 = style->g1;
1836 neww->b1 = style->b1;
1837 neww->flags = style->flags;
1838 neww->char_number = char_number;
1839 neww->mono_space = style->mono_space;
1840 neww->mono_height = style->mono_height;
1841 #ifdef HAVE_FREETYPE
1842 neww->font = freetype_get_allocated_font_name(style);
1843 #endif
1844
1845 if (neww->bitmap.x && (unsigned)neww->bitmap.x * (unsigned)neww->bitmap.y / (unsigned)neww->bitmap.x != (unsigned)neww->bitmap.y) overalloc();
1846 if ((unsigned)neww->bitmap.x * (unsigned)neww->bitmap.y > MAXINT / 3 / sizeof(*primary_data)) overalloc();
1847 primary_data = mem_alloc(3 * neww->bitmap.x * neww->bitmap.y * sizeof(*primary_data));
1848
1849 /* We assume the gamma of HTML styles is in sRGB space */
1850 round_color_sRGB_to_48(&red, &green, &blue, (style->r0 << 16) | (style->g0 << 8) | style->b0);
1851 mix_two_colors(primary_data, found_data,
1852 found_x * found_y,
1853 red, green, blue,
1854 ags_8_to_16(style->r1, (float)((float)(user_gamma tcc_hack) / (float)sRGB_gamma)),
1855 ags_8_to_16(style->g1, (float)((float)(user_gamma tcc_hack) / (float)sRGB_gamma)),
1856 ags_8_to_16(style->b1, (float)((float)(user_gamma tcc_hack) / (float)sRGB_gamma))
1857 );
1858 if (display_optimize) {
1859 /* A correction for LCD */
1860 neww->bitmap.x /= 3;
1861 decimate_3(&primary_data, neww->bitmap.x, neww->bitmap.y);
1862 }
1863 /* We have a buffer with photons */
1864 if (drv->get_empty_bitmap(&neww->bitmap))
1865 goto skip_dither;
1866 if (dither_letters)
1867 dither(primary_data, &neww->bitmap);
1868 else
1869 (*round_fn)(primary_data, &neww->bitmap);
1870 skip_dither:
1871 mem_free(primary_data);
1872 drv->register_bitmap(&neww->bitmap);
1873
1874 mem_free(found_data);
1875
1876 bytes_consumed = neww->bitmap.x * neww->bitmap.y * (drv->depth&7);
1877 /* Number of bytes per pixel in passed bitmaps */
1878 bytes_consumed += (int)sizeof(*neww);
1879 bytes_consumed += (int)sizeof(struct lru_entry);
1880
1881 #ifdef HAVE_FREETYPE
1882 if (!letter) {
1883 lru_insert(&font_cache, neww, &freetype_cache[char_number & (sizeof_freetype_cache - 1)], bytes_consumed);
1884 } else
1885 #endif
1886 {
1887 lru_insert(&font_cache, neww, &letter->color_list, bytes_consumed);
1888 }
1889
1890 return neww;
1891 }
1892
destroy_font_cache_bottom(void)1893 static int destroy_font_cache_bottom(void)
1894 {
1895 struct font_cache_entry *bottom;
1896 bottom = lru_get_bottom(&font_cache);
1897 if (!bottom) return 0;
1898 if (bottom == locked_color_entry) return 0;
1899 #ifdef HAVE_FREETYPE
1900 if (bottom->font) mem_free(bottom->font);
1901 #endif
1902 drv->unregister_bitmap(&bottom->bitmap);
1903 mem_free(bottom);
1904 lru_destroy_bottom(&font_cache);
1905 return 1;
1906 }
1907
1908 /* Prunes the cache to comply with maximum size */
prune_font_cache(void)1909 static int prune_font_cache(void)
1910 {
1911 int r = 0;
1912
1913 while (font_cache.bytes > (unsigned)font_cache_size) {
1914 if (destroy_font_cache_bottom()) {
1915 r = 1;
1916 } else {
1917 break;
1918 }
1919 }
1920 return r;
1921 }
1922
1923 /* Prints a letter to the specified position and
1924 * returns the width of the printed letter */
print_letter(struct graphics_device * device,int x,int y,struct style * style,int char_number)1925 static inline int print_letter(struct graphics_device *device, int x, int y, struct style *style, int char_number)
1926
1927 {
1928 int xw;
1929 struct font_cache_entry *found;
1930 struct font_cache_entry templat;
1931 struct letter *letter;
1932
1933 templat.r0 = style->r0;
1934 templat.r1 = style->r1;
1935 templat.g0 = style->g0;
1936 templat.g1 = style->g1;
1937 templat.b0 = style->b0;
1938 templat.b1 = style->b1;
1939 templat.flags = style->flags;
1940 templat.char_number = char_number;
1941 templat.mono_space = style->mono_space;
1942 templat.mono_height = style->mono_height;
1943 templat.bitmap.y = style->height;
1944 #ifdef HAVE_FREETYPE
1945 templat.font = freetype_get_allocated_font_name(style);
1946 #endif
1947
1948 #ifdef HAVE_FREETYPE
1949 if (style->ft_face) {
1950 found = lru_lookup(&font_cache, &templat, &freetype_cache[char_number & (sizeof_freetype_cache - 1)]);
1951 letter = NULL;
1952 } else
1953 bypass_freetype:
1954 #endif
1955 {
1956 /* Find a suitable letter */
1957 letter = find_stored_letter(style, char_number);
1958 #ifdef DEBUG
1959 if (!letter) internal_error("print_letter could not find a letter - even not the blotch!");
1960 #endif /* #ifdef DEBUG */
1961 found = lru_lookup(&font_cache, &templat, &letter->color_list);
1962 }
1963
1964 if (!found) {
1965 found = supply_color_cache_entry(style, letter, char_number);
1966 #ifdef HAVE_FREETYPE
1967 if (!found)
1968 goto bypass_freetype;
1969 #endif
1970 } else {
1971 locked_color_entry = found;
1972 }
1973 #ifdef HAVE_FREETYPE
1974 if (templat.font) mem_free(templat.font);
1975 #endif
1976 #if 0
1977 drv->fill_area(device, x, y, x + found->bitmap.x, y + found->bitmap.y, drv->get_color(0xff0000));
1978 if (drv->flush) drv->flush(device);
1979 portable_sleep(1);
1980 #endif
1981 drv->draw_bitmap(device, &found->bitmap, x, y);
1982 xw = found->bitmap.x;
1983 if (locked_color_entry != found) internal_error("bad letter lock");
1984 locked_color_entry = NULL;
1985 prune_font_cache();
1986 return xw;
1987 }
1988
1989 /* Must return values that are:
1990 * >=0
1991 * <=height
1992 * at least 1 apart
1993 * Otherwise g_print_text will print nonsense (but won't segfault)
1994 */
get_underline_pos(int height,int * top,int * bottom)1995 static void get_underline_pos(int height, int *top, int *bottom)
1996 {
1997 int thickness, baseline;
1998 thickness=(height+15)/16;
1999 baseline=height/7;
2000 if (baseline<=0) baseline=1;
2001 if (thickness>baseline) thickness=baseline;
2002 *top=height-baseline;
2003 *bottom=*top+thickness;
2004 }
2005
2006 /* *width will be advanced by the width of the text */
g_print_text(struct graphics_device * device,int x,int y,struct style * style,unsigned char * text,int * width)2007 void g_print_text(struct graphics_device *device, int x, int y, struct style *style, unsigned char *text, int *width)
2008 {
2009 int top_underline, bottom_underline, original_width, my_width;
2010 unsigned char original_flags;
2011 struct rect saved_clip;
2012
2013 if (y + style->height <= device->clip.y1 || y >= device->clip.y2)
2014 goto o;
2015 if (style->flags & FF_UNDERLINE) {
2016 /* Underline */
2017 if (!width) {
2018 width = &my_width;
2019 *width = 0;
2020 }
2021 original_flags = style->flags;
2022 original_width = *width;
2023 style->flags &= ~FF_UNDERLINE;
2024 get_underline_pos(style->height, &top_underline, &bottom_underline);
2025 restrict_clip_area(device, &saved_clip, 0, 0, device->size.x2, y + top_underline);
2026 g_print_text(device, x, y, style, text, width);
2027 set_clip_area(device, &saved_clip);
2028 if (bottom_underline - top_underline == 1) {
2029 /* Line */
2030 drv->draw_hline(device, x, y + top_underline, safe_add(x, *width) - original_width, style->underline_color);
2031 } else {
2032 /* Area */
2033 drv->fill_area(device, x, y + top_underline, safe_add(x, *width) - original_width, y + bottom_underline, style->underline_color);
2034 }
2035 if (bottom_underline < style->height) {
2036 /* Do the bottom half only if the underline is above
2037 * the bottom of the letters.
2038 */
2039 *width = original_width;
2040 restrict_clip_area(device, &saved_clip, 0, y + bottom_underline, device->size.x2, device->size.y2);
2041 g_print_text(device, x, y, style, text, width);
2042 set_clip_area(device, &saved_clip);
2043 }
2044 style->flags = original_flags;
2045 return;
2046 }
2047 while (*text) {
2048 int p;
2049 int u;
2050 GET_UTF_8(text, u);
2051 /* 00-09, 0b-1f, 80, 81, 84, 86-9f ignorovat
2052 * 0a = LF
2053 * 82 = ' '
2054 * 83 = nobrk
2055 * 85 = radkovy zlom
2056 * a0 = NBSP
2057 * ad = soft hyphen
2058 */
2059 #if 0
2060 if ( (u>=0x00&&u<=0x09)||
2061 (u>=0x0b&&u<=0x1f)||
2062 u==0x80||
2063 u==0x82||
2064 u==0x84||
2065 (u>=0x86&&u<=0x9f)
2066 )continue;
2067 if (u==0x82)u=' ';
2068 #endif
2069 /* stare Mikulasovo patchovani, musim to opravit -- Brain */
2070 if (!u || u == 0xad)
2071 continue;
2072 if (u == 0x01 || u == 0xa0) u = ' ';
2073 p = print_letter(device, x, y, style, u);
2074 x += p;
2075 if (width) {
2076 *width = safe_add(*width, p);
2077 continue;
2078 }
2079 if (x >= device->clip.x2)
2080 return;
2081 }
2082 return;
2083 o:
2084 if (width) {
2085 int qw = g_text_width(style, text);
2086 *width = safe_add(*width, qw);
2087 }
2088 }
2089
2090 /* 0=equality 1=inequality */
compare_font_entries(void * entry,void * templat)2091 static int compare_font_entries(void *entry, void *templat)
2092 {
2093 struct font_cache_entry *e1 = entry;
2094 struct font_cache_entry *e2 = templat;
2095
2096 if (e1->r0 != e2->r0) return 1;
2097 if (e1->g0 != e2->g0) return 1;
2098 if (e1->b0 != e2->b0) return 1;
2099 if (e1->r1 != e2->r1) return 1;
2100 if (e1->g1 != e2->g1) return 1;
2101 if (e1->b1 != e2->b1) return 1;
2102 if (e1->flags != e2->flags) return 1;
2103 if (e1->char_number != e2->char_number) return 1;
2104 if (e1->mono_space != e2->mono_space) return 1;
2105 if (e1->mono_space >= 0) {
2106 if (e1->mono_height != e2->mono_height) return 1;
2107 }
2108 if (e1->bitmap.y != e2->bitmap.y) return 1;
2109 #ifdef HAVE_FREETYPE
2110 if (!e1->font != !e2->font) return 1;
2111 if (e1->font && strcmp(cast_const_char e1->font, cast_const_char e2->font)) return 1;
2112 #endif
2113 return 0;
2114 }
2115
2116 /* If the cache already exists, it is destroyed and reallocated. If you call it with the same
2117 * size argument, only a cache flush will yield.
2118 */
init_font_cache(void)2119 static void init_font_cache(void)
2120 {
2121 lru_init(&font_cache, &compare_font_entries);
2122 }
2123
2124 /* Ensures there are no lru_entry objects allocated - destroys them.
2125 * Also destroys the bitmaps asociated with them. Does not destruct the
2126 font_cache per se.
2127 */
destroy_font_cache(void)2128 static void destroy_font_cache(void)
2129 {
2130 while (destroy_font_cache_bottom())
2131 ;
2132 if (lru_get_bottom(&font_cache))
2133 internal_error("destroy_font_cache: cache not freed due to locks");
2134 }
2135
2136 /* Returns 0 in case the char is not found. */
g_get_width(struct style * style,unsigned charcode)2137 static inline int g_get_width(struct style *style, unsigned charcode)
2138 {
2139 int x, y, width;
2140
2141 if (!charcode || charcode == 0xad) return 0;
2142 if (charcode == 0x01 || charcode == 0xa0) charcode = ' ';
2143 if (style->mono_space >= 0) {
2144 x = style->mono_space;
2145 y = style->mono_height;
2146 } else load_metric(style, charcode, &x, &y);
2147 if (!(x && y)) width = 0;
2148 else width = compute_width(x, y, style->height);
2149 return width;
2150 }
2151
g_text_width(struct style * style,unsigned char * text)2152 int g_text_width(struct style *style, unsigned char *text)
2153 {
2154 int w = 0;
2155 while (*text) {
2156 int u;
2157 int qw;
2158 GET_UTF_8(text, u);
2159 qw = g_get_width(style, u);
2160 w = safe_add(w, qw);
2161 }
2162 return w;
2163 }
2164
g_char_width(struct style * style,unsigned charcode)2165 int g_char_width(struct style *style, unsigned charcode)
2166 {
2167 return g_get_width(style, charcode);
2168 }
2169
g_wrap_text(struct wrap_struct * w)2170 int g_wrap_text(struct wrap_struct *w)
2171 {
2172 unsigned char *init_text = w->text;
2173 while (*w->text) {
2174 int u;
2175 int s;
2176 unsigned char *l_text = w->text;
2177 if (*l_text == ' ') w->last_wrap = l_text,
2178 w->last_wrap_obj = w->obj;
2179 GET_UTF_8(w->text, u);
2180 if (!u) continue;
2181 s = g_get_width(w->style, u);
2182 w->pos = safe_add(w->pos, s);
2183 if (w->pos <= w->width) {
2184 c:
2185 if (u != 0xad || *w->text == ' ' || w->force_break) continue;
2186 s = g_char_width(w->style, '-');
2187 if (safe_add(w->pos, s) <= w->width || (!w->last_wrap && !w->last_wrap_obj)) {
2188 w->last_wrap = l_text;
2189 w->last_wrap_obj = w->obj;
2190 continue;
2191 }
2192 }
2193 if (w->force_break && !w->last_wrap && l_text != init_text) {
2194 w->last_wrap = l_text;
2195 w->last_wrap_obj = w->obj;
2196 }
2197 if (!w->last_wrap && !w->last_wrap_obj) goto c;
2198 return 0;
2199 }
2200 return 1;
2201 }
2202
update_aspect(void)2203 void update_aspect(void)
2204 {
2205 aspect = (int)(65536 * bfu_aspect + 0.5);
2206 destroy_font_cache();
2207 }
2208
flush_bitmaps(int flush_font,int flush_images,int redraw_all)2209 void flush_bitmaps(int flush_font, int flush_images, int redraw_all)
2210 {
2211 if (flush_font)
2212 destroy_font_cache();
2213 if (flush_images)
2214 gamma_stamp++;
2215 if (redraw_all)
2216 cls_redraw_all_terminals();
2217 }
2218
fontcache_info(int type)2219 my_uintptr_t fontcache_info(int type)
2220 {
2221 switch (type) {
2222 case CI_BYTES:
2223 return font_cache.bytes;
2224 case CI_FILES:
2225 return font_cache.items;
2226 default:
2227 internal_error("fontcache_info: query %d", type);
2228 return 0;
2229 }
2230 }
2231
shrink_font_cache(int u)2232 static int shrink_font_cache(int u)
2233 {
2234 int freed_something = 0;
2235 int has_something;
2236 if (u == SH_CHECK_QUOTA) {
2237 freed_something = prune_font_cache();
2238 }
2239 if (u == SH_FREE_ALL) {
2240 while (destroy_font_cache_bottom())
2241 freed_something = 1;
2242 }
2243 if (u == SH_FREE_SOMETHING) {
2244 freed_something = destroy_font_cache_bottom();
2245 }
2246 has_something = !!lru_get_bottom(&font_cache);
2247 return (freed_something ? ST_SOMETHING_FREED : 0) |
2248 (has_something ? 0 : ST_CACHE_EMPTY);
2249 }
2250
init_dip(void)2251 void init_dip(void)
2252 {
2253 init_font_cache();
2254 update_aspect();
2255 register_cache_upcall(shrink_font_cache, MF_GPI, cast_uchar "fontcache");
2256 }
2257
g_invert_style(struct style * old)2258 struct style *g_invert_style(struct style *old)
2259 {
2260 struct style *st;
2261 st = mem_alloc(sizeof(struct style));
2262 st->refcount = 1;
2263 st->r0 = old->r1;
2264 st->g0 = old->g1;
2265 st->b0 = old->b1;
2266 st->r1 = old->r0;
2267 st->g1 = old->g0;
2268 st->b1 = old->b0;
2269 st->height = old->height;
2270 st->flags = old->flags;
2271 #ifdef HAVE_FREETYPE
2272 st->ft_face = old->ft_face;
2273 #endif
2274 if (st->flags & FF_UNDERLINE) {
2275 /* We have to get a foreground color for underlining */
2276 st->underline_color = dip_get_color_sRGB((st->r1 << 16) | (st->g1 << 8) | (st->b1));
2277 }
2278 st->mono_space = old->mono_space;
2279 st->mono_height = old->mono_height;
2280 return st;
2281 }
2282
hack_rgb(int rgb)2283 int hack_rgb(int rgb)
2284 {
2285 if (((drv->depth >> 3) & 0x1f) <= 4) {
2286 int r,g,b;
2287 r=(rgb>>16)&255;
2288 g=(rgb>>8)&255;
2289 b=rgb&255;
2290 if (r == g && g == b) {
2291 if (r < 128) return 0;
2292 else return 0xffffff;
2293 }
2294 }
2295 return rgb;
2296 }
2297
2298 /* Never returns NULL. */
g_get_style_font(int fg,int bg,int size,int fflags,unsigned char * font)2299 struct style *g_get_style_font(int fg, int bg, int size, int fflags, unsigned char *font)
2300 {
2301 struct style *st;
2302
2303 bg = hack_rgb(bg);
2304
2305 st = mem_alloc(sizeof(struct style));
2306 st->refcount = 1;
2307 st->r0 = bg >> 16;
2308 st->g0 = (bg >> 8) & 255;
2309 st->b0 = bg & 255;
2310 st->r1 = fg >> 16;
2311 st->g1 = (fg >> 8) & 255;
2312 st->b1 = fg & 255;
2313 if (size <= 0) size = 1;
2314 st->height = size;
2315 st->flags = (unsigned char)fflags;
2316 #ifdef HAVE_FREETYPE
2317 if (!font)
2318 st->ft_face = freetype_flags_to_face(fflags);
2319 else
2320 st->ft_face = freetype_get_font(font);
2321 #endif
2322 if (fflags & FF_UNDERLINE) {
2323 /* We have to get a foreground color for underlining */
2324 st->underline_color = dip_get_color_sRGB(fg);
2325 }
2326 if (fflags & FF_MONOSPACED)
2327 load_metric(st, ' ', &st->mono_space, &st->mono_height);
2328 else
2329 st->mono_space = -1;
2330
2331 return st;
2332 }
2333
g_get_style(int fg,int bg,int size,int fflags)2334 struct style *g_get_style(int fg, int bg, int size, int fflags)
2335 {
2336 return g_get_style_font(fg, bg, size, fflags, NULL);
2337 }
2338
g_clone_style(struct style * st)2339 struct style *g_clone_style(struct style *st)
2340 {
2341 st->refcount++;
2342 return st;
2343 }
2344
g_free_style(struct style * st)2345 void g_free_style(struct style *st)
2346 {
2347 if (--st->refcount) return;
2348 #ifdef HAVE_FREETYPE
2349 if (st->ft_face)
2350 freetype_free_font(st->ft_face);
2351 #endif
2352 mem_free(st);
2353 }
2354
2355 tcount gamma_stamp = 1; /* stamp counter for gamma changes */
2356
2357 long gamma_cache_color_1;
2358 int gamma_cache_rgb_1;
2359 long gamma_cache_color_2;
2360 int gamma_cache_rgb_2;
2361
2362 /* IEC 61966-2-1
2363 * Input gamma: sRGB space (directly from HTML, i. e. unrounded)
2364 * Output: color index for graphics driver that is closest to the
2365 * given sRGB value.
2366 * We assume unsigned short holds at least 16 bits. */
real_dip_get_color_sRGB(int rgb)2367 long real_dip_get_color_sRGB(int rgb)
2368 {
2369 unsigned short r, g, b;
2370 int hacked_rgb, new_rgb;
2371
2372 hacked_rgb = hack_rgb(rgb);
2373
2374 round_color_sRGB_to_48(&r, &g, &b, hacked_rgb);
2375 r = ags_16_to_8(r, (float)(1 / (float)(display_red_gamma tcc_hack)));
2376 g = ags_16_to_8(g, (float)(1 / (float)(display_green_gamma tcc_hack)));
2377 b = ags_16_to_8(b, (float)(1 / (float)(display_blue_gamma tcc_hack)));
2378 new_rgb = b | (g << 8) | (r << 16);
2379
2380 gamma_cache_rgb_2 = gamma_cache_rgb_1;
2381 gamma_cache_color_2 = gamma_cache_color_1;
2382
2383 gamma_cache_rgb_1 = rgb;
2384 /* The get_color takes values with gamma of display_*_gamma */
2385 return gamma_cache_color_1 = drv->get_color(new_rgb);
2386 }
2387
2388 #include "links_ic.inc"
2389
get_links_icon(unsigned char ** data,int * width,int * height,ssize_t * skip,int pad)2390 void get_links_icon(unsigned char **data, int *width, int *height, ssize_t *skip, int pad)
2391 {
2392 struct bitmap b;
2393 unsigned short *tmp1;
2394 float g = (float)((float)(user_gamma tcc_hack) / (float)sRGB_gamma);
2395
2396 b.x = 48;
2397 b.y = 48;
2398 *width = b.x;
2399 *height = b.y;
2400 b.skip = b.x * (drv->depth & 7);
2401 while (b.skip % pad) b.skip++;
2402 *skip = b.skip;
2403 b.data = *data = mem_alloc(b.skip * b.y);
2404 tmp1 = mem_alloc(6 * b.y * b.x);
2405 agx_24_to_48(tmp1, links_icon, b.x * b.y, g, g, g);
2406 (*round_fn)(tmp1, &b);
2407 mem_free(tmp1);
2408 }
2409
qb_palette(unsigned r_max,unsigned g_max,unsigned b_max,unsigned r,unsigned g,unsigned b,unsigned scale,unsigned rgb[3])2410 static inline void qb_palette(unsigned r_max, unsigned g_max, unsigned b_max, unsigned r, unsigned g, unsigned b, unsigned scale, unsigned rgb[3])
2411 {
2412 rgb[0] = (r * scale + r_max / 2) / r_max;
2413 rgb[1] = (g * scale + g_max / 2) / g_max;
2414 rgb[2] = (b * scale + b_max / 2) / b_max;
2415 }
2416
q_palette(unsigned size,unsigned color,unsigned scale,unsigned rgb[3])2417 void q_palette(unsigned size, unsigned color, unsigned scale, unsigned rgb[3])
2418 {
2419 if (color >= size) {
2420 rgb[0] = rgb[1] = rgb[2] = 0;
2421 return;
2422 }
2423 switch (size) {
2424 case 8:
2425 qb_palette(1, 1, 1, color >> 2, (color >> 1) & 1, color & 1, scale, rgb);
2426 break;
2427 case 16:
2428 qb_palette(1, 3, 1, color >> 3, (color >> 1) & 3, color & 1, scale, rgb);
2429 break;
2430 case 216:
2431 qb_palette(5, 5, 5, color / 36, color / 6 % 6, color % 6, scale, rgb);
2432 break;
2433 case 256:
2434 qb_palette(7, 7, 3, color >> 5, (color >> 2) & 7, color & 3, scale, rgb);
2435 break;
2436 case 32768:
2437 qb_palette(31, 31, 31, color >> 10, (color >> 5) & 31, color & 31, scale, rgb);
2438 break;
2439 case 65536:
2440 qb_palette(31, 63, 31, color >> 11, (color >> 5) & 63, color & 31, scale, rgb);
2441 break;
2442 case 16777216:
2443 qb_palette(255, 255, 255, color >> 16, (color >> 8) & 255, color & 255, scale, rgb);
2444 break;
2445 default:
2446 internal_error("q_palette: invalid size %u", size);
2447 }
2448 }
2449
rgb_distance(int r1,int g1,int b1,int r2,int g2,int b2)2450 double rgb_distance(int r1, int g1, int b1, int r2, int g2, int b2)
2451 {
2452 double diff_r, diff_g, diff_b;
2453 diff_r = (r1 - r2) * .30;
2454 diff_r *= diff_r;
2455 diff_g = (g1 - g2) * .59;
2456 diff_g *= diff_g;
2457 diff_b = (b1 - b2) * .11;
2458 diff_b *= diff_b;
2459 return diff_r + diff_g + diff_b;
2460 }
2461
2462 #endif /* G */
2463