1 /* img.c
2 * Generic image decoding and PNG and JPG decoders.
3 * (c) 2002 Karel 'Clock' Kulhavy
4 * This is a part of the Links program, released under GPL.
5
6 * Used in graphics mode of Links only
7 TODO: odstranit zbytecne ditherovani z strip_optimized header_dimensions_known,
8 protoze pozadi obrazku musi byt stejne jako pozadi stranky, a to se nikdy
9 neditheruje, protoze je to vzdy jednolita barva. Kdyz uz to nepujde
10 odstranit tak tam aspon dat fixne zaokrouhlovani.
11 TODO: dodelat stripy do jpegu a png a tiff.
12 */
13
14 #include "links.h"
15
16 #ifdef G
17
18 #define RESTART_SIZE 8192
19 /* Size of biggest chunk of compressed data that is processed in one run */
20
21 static struct g_object_image *global_goi;
22 struct cached_image *global_cimg;
23 int end_callback_hit;
24
is_image_size_sane(ssize_t x,ssize_t y)25 static int is_image_size_sane(ssize_t x, ssize_t y)
26 {
27 size_t a;
28 if (x < 0 || y < 0) return 0;
29 if (x >= MAXINT || y >= MAXINT) return 0;
30 a = (size_t)x * (size_t)y * (drv->depth & 7);
31 if (y && (size_t)a / (size_t)y / (drv->depth & 7) != (size_t)x) return 0;
32 return a <= MAX_SIZE_T / 2;
33 }
34
35 /* mem_free(cimg->decoder) */
destroy_decoder(struct cached_image * cimg)36 static void destroy_decoder (struct cached_image *cimg)
37 {
38 if (cimg->decoder){
39 switch(cimg->image_type){
40 case IM_PNG:
41 png_destroy_decoder(cimg);
42 break;
43 #ifdef HAVE_JPEG
44 case IM_JPG:
45 jpeg_destroy_decoder(cimg);
46 break;
47 #endif /* #ifdef HAVE_JPEG */
48 case IM_GIF:
49 gif_destroy_decoder(cimg);
50 break;
51 case IM_XBM:
52 /* do nothing */
53 break;
54 #ifdef HAVE_TIFF
55 case IM_TIFF:
56 tiff_destroy_decoder(cimg);
57 break;
58 #endif
59 #ifdef HAVE_SVG
60 case IM_SVG:
61 svg_destroy_decoder(cimg);
62 break;
63 #endif
64 }
65 mem_free(cimg->decoder);
66 }
67 }
68
mem_free_buffer(struct cached_image * cimg)69 static void mem_free_buffer(struct cached_image *cimg)
70 {
71 mem_free(cimg->buffer);
72 }
73
img_destruct_image(struct g_object * object)74 static void img_destruct_image(struct g_object *object)
75 {
76 struct g_object_image *goi = get_struct(object, struct g_object_image, goti.go);
77
78 if (goi->orig_src) mem_free(goi->orig_src);
79 if (goi->alt) mem_free(goi->alt);
80 if (goi->name) mem_free(goi->name);
81 if (goi->src) mem_free(goi->src);
82 release_image_map(goi->goti.map);
83 if (goi->list_entry.next) del_from_list(goi);
84 if (goi->goti.go.xw && goi->goti.go.yw) {
85 /* At least one dimension is zero */
86 deref_cached_image(goi->cimg);
87 }
88 mem_free(goi);
89 }
90
91 /* Frees all data allocated by cached_image including cached image itself */
img_destruct_cached_image(struct cached_image * cimg)92 void img_destruct_cached_image(struct cached_image *cimg)
93 {
94 switch (cimg->state){
95 case 0:
96 case 1:
97 case 2:
98 case 3:
99 case 9:
100 case 11:
101 break;
102
103 case 12:
104 case 14:
105 if (cimg->gamma_table) mem_free(cimg->gamma_table);
106 if (cimg->bmp_used){
107 drv->unregister_bitmap(&(cimg->bmp));
108 }
109 if (cimg->strip_optimized){
110 if (cimg->dregs) mem_free(cimg->dregs);
111 }else{
112 mem_free_buffer(cimg);
113 }
114 /*-fallthrough*/
115 case 8:
116 case 10:
117 destroy_decoder(cimg);
118 break;
119
120 case 13:
121 case 15:
122 drv->unregister_bitmap(&(cimg->bmp));
123 break;
124
125 #ifdef DEBUG
126 default:
127 fprintf(stderr, "img_destruct_cached_image: state=%d\n", cimg->state);
128 internal_error("Invalid state in struct cached_image");
129 #endif /* #ifdef DEBUG */
130 }
131 mem_free(cimg->url);
132 mem_free(cimg);
133 }
134
135 /* You throw in a vertical dimension of image and it returns
136 * new dimension according to the aspect ratio and user-set image
137 * scaling factor. When scaling factor is 100% and screen pixels
138 * are non-square, the picture will be always in one dimension
139 * untouched and in the second _ENLARGED_. So that no information
140 * in the picture will be lost.
141 * Input may be <0. In this case output=input
142 * Input may be 0. In this case output=0.
143 * If input is >0 the output is also >0.
144 */
img_scale_h(unsigned scale,ssize_t in)145 static ssize_t img_scale_h(unsigned scale, ssize_t in)
146 {
147 ssize_t out;
148 /* We assume unsigned long holds at least 32 bits */
149 unsigned long pre;
150
151 if (in<=0) return in;
152 pre=((unsigned long)(aspect<65536UL?65536UL:aspect)*scale+128)>>8;
153 out=(size_t)(((unsigned long)in*pre+12800UL)/25600UL);
154 if (out<1) out=1;
155 return out;
156 }
157
img_scale_v(unsigned scale,ssize_t in)158 static ssize_t img_scale_v(unsigned scale, ssize_t in)
159 {
160 ssize_t out;
161 unsigned long divisor;
162
163 if (in<=0) return in;
164 divisor=(100*(aspect>=65536UL?65536UL:aspect)+128)>>8;
165 out=(ssize_t)(((unsigned long)in*(scale*256)+(divisor>>1))/divisor);
166 if (out<1) out=1;
167 return out;
168 }
169
170 /* Returns height (pixels) for prescribed width (pixels). Honours aspect. */
width2height(double width_px,double width_mm,double height_mm)171 static ssize_t width2height(double width_px, double width_mm, double height_mm)
172 {
173 ssize_t height_px;
174
175 if (width_px<=0) return 0;
176 height_px=(ssize_t)((height_mm*width_px*65536)/(aspect*width_mm));
177 if (height_px<1) height_px=1;
178 return height_px;
179
180 }
181
182 /* Returns width (pixels) for prescribed height (pixels). Honours aspect. */
height2width(double height_px,double width_mm,double height_mm)183 static ssize_t height2width(double height_px, double width_mm, double height_mm)
184 {
185 ssize_t width_px;
186
187 if (height_px<=0) return 0;
188 width_px=(ssize_t)((width_mm*height_px*aspect)/(65536*height_mm));
189 if (width_px<1) width_px=1;
190 return width_px;
191
192 }
193
194 /* Compute 8-bit background for filling buffer with cimg->*_gamma
195 * (performs rounding) */
compute_background_8(struct cached_image * cimg,unsigned char rgb[3])196 void compute_background_8(struct cached_image *cimg, unsigned char rgb[3])
197 {
198 unsigned short red, green, blue;
199
200 round_color_sRGB_to_48(&red, &green, &blue, cimg->background_color);
201 rgb[0] = ags_16_to_8(red, (float)(cimg->red_gamma/(float)(user_gamma tcc_hack)));
202 rgb[1] = ags_16_to_8(green, (float)(cimg->green_gamma/(float)(user_gamma tcc_hack)));
203 rgb[2] = ags_16_to_8(blue, (float)(cimg->blue_gamma/(float)(user_gamma tcc_hack)));
204 }
205
206 /* updates cimg state when header dimensions are know. Only allowed to be called
207 * in state 8 and 10.
208 * Allocates right amount of memory into buffer, formats it (with background or
209 * zeroes, depens on buffer_bytes_per_pixel). Updates dimensions (xww and yww)
210 * according to newly known header dimensions. Fills in gamma_stamp, bmp_used
211 * (zero because we not bother with generating bitmap here)
212 * and rows_added.
213 * Resets strip_optimized if image will be scaled or
214 * Allocates dregs if on exit strip_optimized is nonzero.
215 * Allocates and computes gamma_table, otherwise
216 * sets gamma_table to NULL. Also doesn't make gamma table if image contains less
217 * than 1024 pixels (it would be probably a waste of time).
218 * Output state is always 12 (from input state 8) or 14 (from input state 10).
219 *
220 * The caller must have set the following elements of cimg:
221 * width
222 * height
223 * buffer_bytes_per_pixel
224 * red_gamma
225 * green_gamma
226 * blue_gamma
227 * strip_optimized
228 */
header_dimensions_known(struct cached_image * cimg)229 int header_dimensions_known(struct cached_image *cimg)
230 {
231 unsigned short red, green, blue;
232
233 #ifdef DEBUG
234 if ((cimg->state^8)&13){
235 fprintf(stderr,"cimg->state=%d\n",cimg->state);
236 internal_error("Invalid state in header_dimensions_known");
237 }
238 #endif /* #ifdef DEBUG */
239 if (cimg->width<1||cimg->height<1){
240 /*fprintf(stderr,"width=%d height=%d\n",cimg->width, cimg->height);*/
241 return 1;
242 }
243 if (!is_image_size_sane(cimg->width, cimg->height)) {
244 return 1;
245 }
246 if (cimg->wanted_xw<0){
247 /* Unspecified width */
248 if (cimg->wanted_yw<0){
249 /* Unspecified neither width nor height */
250 cimg->xww=img_scale_h(cimg->scale, cimg->width);
251 cimg->yww=img_scale_v(cimg->scale, cimg->height);
252 }else{
253 /* Unspecified width specified height */
254 cimg->xww=height2width(cimg->yww,
255 cimg->width, cimg->height);
256 if (cimg->xww<=0) cimg->xww=1;
257
258 }
259 }else{
260 /* Specified width */
261 if (cimg->wanted_yw<0){
262 /* Unspecified height, specified width */
263 cimg->yww=width2height(cimg->xww,
264 cimg->width, cimg->height);
265 if (cimg->yww<=0) cimg->yww=1;
266 }else if (cimg->wanted_xyw_meaning==MEANING_AUTOSCALE){
267 /* Specified height and width and autoscale meant */
268 /* Try first to nail the height */
269 cimg->yww=cimg->wanted_yw;
270 cimg->xww=height2width(cimg->yww,
271 cimg->width, cimg->height);
272 if (cimg->xww>cimg->wanted_xw)
273 {
274 /* Width too much, we nail the width */
275 cimg->xww=cimg->wanted_xw;
276 cimg->yww=width2height(cimg->xww,
277 cimg->width, cimg->height);
278 }
279
280 /* Some sanity checks */
281 if (cimg->xww<=0) cimg->xww=1;
282 if (cimg->yww<=0) cimg->yww=1;
283 }
284 }
285 if (!is_image_size_sane(cimg->xww, cimg->yww)) {
286 cimg->xww = cimg->width;
287 cimg->yww = cimg->height;
288 }
289
290 #ifdef HAVE_SVG
291 if (cimg->image_type == IM_SVG) {
292 /* SVG images are scaled using the cairo library, not the Links scaler */
293 cimg->width = cimg->xww;
294 cimg->height = cimg->yww;
295 }
296 #endif
297
298 if (cimg->width!=cimg->xww||cimg->height!=cimg->yww) cimg->strip_optimized=0;
299 cimg->gamma_stamp=gamma_stamp;
300 if (cimg->strip_optimized){
301 struct bitmap tmpbmp;
302 unsigned short *buf_16;
303 ssize_t i;
304
305 tmpbmp.x = (int)cimg->width;
306 tmpbmp.y = 1;
307 /* No buffer, bitmap is valid from the very beginning */
308 cimg->bmp.x = (int)cimg->width;
309 cimg->bmp.y = (int)cimg->height;
310 if (drv->get_empty_bitmap(&(cimg->bmp))) {
311 cimg->dregs = NULL;
312 goto skip_img;
313 }
314 if ((size_t)cimg->width > MAX_SIZE_T / sizeof(*buf_16) / 3) overalloc();
315 buf_16 = mem_alloc(sizeof(*buf_16) * 3 * (size_t)cimg->width);
316 round_color_sRGB_to_48(&red, &green, &blue
317 , cimg->background_color);
318 mix_one_color_48(buf_16,cimg->width, red, green, blue);
319 #ifdef DEBUG
320 if (cimg->height<=0){
321 fprintf(stderr,"cimg->height=%ld\n", (long)cimg->height);
322 internal_error("Invalid cimg->height in strip_optimized section of header_dimensions_known");
323 }
324 #endif /* #ifdef DEBUG */
325 /* The skip is uninitialized here and is read by dither_start
326 * but is not used in any malicious way so it doesn't matter
327 */
328 tmpbmp.data = cimg->bmp.data;
329 tmpbmp.skip = cimg->bmp.skip;
330 cimg->dregs=dither_images?dither_start(buf_16,&tmpbmp):NULL;
331 tmpbmp.data=(unsigned char *)tmpbmp.data+cimg->bmp.skip;
332 if (cimg->dregs)
333 for (i=cimg->height-1;i;i--){
334 dither_restart(buf_16,&tmpbmp,cimg->dregs);
335 tmpbmp.data=(unsigned char *)tmpbmp.data+cimg->bmp.skip;
336 }
337 else
338 for (i=cimg->height-1;i;i--){
339 (*round_fn)(buf_16,&tmpbmp);
340 tmpbmp.data=(unsigned char *)tmpbmp.data+cimg->bmp.skip;
341 }
342 mem_free(buf_16);
343 skip_img:
344 drv->register_bitmap(&(cimg->bmp));
345 if(cimg->dregs) memset(cimg->dregs,0,cimg->width*sizeof(*cimg->dregs)*3);
346 cimg->bmp_used=1; /* Nonzero value */
347 /* This ensures the dregs are none and because strip
348 * optimization is unusable in interlaced pictures,
349 * this saves the zeroing out at the beginning of the
350 * decoder itself.
351 */
352 }else {
353 cimg->rows_added=1;
354 cimg->bmp_used=0;
355 if (cimg->width && (size_t)cimg->width * (size_t)cimg->height / (size_t)cimg->width != (size_t)cimg->height) overalloc();
356 cimg->buffer = mem_alloc_mayfail((size_t)cimg->width * (size_t)cimg->height * (size_t)cimg->buffer_bytes_per_pixel);
357 if (!cimg->buffer)
358 return 1;
359 if (cimg->buffer_bytes_per_pixel==4
360 ||cimg->buffer_bytes_per_pixel==4
361 *sizeof(unsigned short))
362 {
363 /* Make the buffer contain full transparency */
364 memset(cimg->buffer, 0, (size_t)cimg->width * (size_t)cimg->height * (size_t)cimg->buffer_bytes_per_pixel);
365 }else{
366 /* Fill the buffer with background color */
367 if (cimg->buffer_bytes_per_pixel > 4){
368 /* 16-bit */
369 unsigned short red, green, blue;
370
371 round_color_sRGB_to_48(&red, &green, &blue, cimg->background_color);
372
373 red=ags_16_to_16(red, (float)(cimg->red_gamma / (float)(user_gamma tcc_hack)));
374 green=ags_16_to_16(green, (float)(cimg->green_gamma / (float)(user_gamma tcc_hack)));
375 blue=ags_16_to_16(blue, (float)(cimg->blue_gamma / (float)(user_gamma tcc_hack)));
376 mix_one_color_48((unsigned short *)cimg->buffer, cimg->width*cimg->height, red, green, blue);
377 } else {
378 unsigned char rgb[3];
379
380 /* 8-bit */
381 compute_background_8(cimg, rgb);
382 mix_one_color_24(cimg->buffer, cimg->width * cimg->height, rgb[0], rgb[1], rgb[2]);
383 }
384 }
385 }
386 if (cimg->buffer_bytes_per_pixel<=4&&cimg->width*cimg->height>=1024){
387 make_gamma_table(cimg);
388 }else if (cimg->buffer_bytes_per_pixel>=6&&cimg->width*cimg->height>=262144){
389 make_gamma_table(cimg);
390 }else cimg->gamma_table=NULL;
391 cimg->state|=4; /* Update state */
392 return 0;
393 }
394
395 /* Fills "tmp" buffer with the resulting data and does not free the input
396 * buffer. May be called only in states 12 and 14 of cimg
397 */
buffer_to_16(unsigned short * tmp,struct cached_image * cimg,unsigned char * buffer,ssize_t height)398 static unsigned short *buffer_to_16(unsigned short *tmp, struct cached_image *cimg, unsigned char *buffer, ssize_t height)
399 {
400 unsigned short red, green, blue;
401
402 #ifdef DEBUG
403 if (cimg->state != 12 && cimg->state != 14){
404 fprintf(stderr, "cimg->state=%d\n", cimg->state);
405 internal_error("invalid state in buffer_to_16");
406 }
407 #endif /* #ifdef DEBUG */
408 switch (cimg->buffer_bytes_per_pixel) {
409 case 3:
410 if (cimg->gamma_table) {
411 agx_24_to_48_table(tmp, buffer, cimg->width*height, cimg->gamma_table);
412 } else {
413 agx_24_to_48(tmp, buffer, cimg->width * height,
414 (float)((float)(user_gamma tcc_hack) / cimg->red_gamma),
415 (float)((float)(user_gamma tcc_hack) / cimg->green_gamma),
416 (float)((float)(user_gamma tcc_hack) / cimg->blue_gamma));
417 }
418 break;
419
420 case 3 * sizeof(unsigned short):
421 if (cimg->gamma_table) {
422 agx_48_to_48_table(tmp, (unsigned short *)buffer, cimg->width * height, cimg->gamma_table);
423 } else {
424 agx_48_to_48(tmp, (unsigned short *)buffer, cimg->width * height,
425 (float)((float)(user_gamma tcc_hack) / cimg->red_gamma),
426 (float)((float)(user_gamma tcc_hack) / cimg->green_gamma),
427 (float)((float)(user_gamma tcc_hack) / cimg->blue_gamma));
428 }
429 break;
430
431 /* Alpha's: */
432 case 4:
433 round_color_sRGB_to_48(&red,&green,&blue,cimg->background_color);
434 if (cimg->gamma_table) {
435 agx_and_uc_32_to_48_table(tmp, buffer, cimg->width * height, cimg->gamma_table, red, green, blue);
436 } else {
437 agx_and_uc_32_to_48(tmp,buffer, cimg->width*height,
438 (float)((float)(user_gamma tcc_hack) / cimg->red_gamma),
439 (float)((float)(user_gamma tcc_hack) / cimg->green_gamma),
440 (float)((float)(user_gamma tcc_hack) / cimg->blue_gamma),
441 red, green, blue);
442 }
443 break;
444
445 case 4 * sizeof(unsigned short):
446 round_color_sRGB_to_48(&red, &green, &blue, cimg->background_color);
447 if (cimg->gamma_table) {
448 agx_and_uc_64_to_48_table(tmp, (unsigned short *)buffer, cimg->width * height, cimg->gamma_table, red, green, blue);
449 } else {
450 agx_and_uc_64_to_48(tmp, (unsigned short *)buffer, cimg->width * height,
451 (float)((float)(user_gamma tcc_hack) / cimg->red_gamma),
452 (float)((float)(user_gamma tcc_hack) / cimg->green_gamma),
453 (float)((float)(user_gamma tcc_hack) / cimg->blue_gamma),
454 red,green,blue);
455 }
456 break;
457
458 #ifdef DEBUG
459 default:
460 internal_error("buffer_to_16: unknown mem organization");
461 #endif /* #ifdef DEBUG */
462
463 }
464 return tmp;
465 }
466
467 /* Returns allocated buffer with the resulting data and does not free the input
468 * buffer. May be called only in states 12 and 14 of cimg
469 * use_strip: 1 if the image is already registered and prepare_strip and
470 * commit_strip is to be used
471 * 0: if the image is not yet registered and instead one big register_bitmap
472 * will be used eventually
473 * dregs must be externally allocated and contain required value or must be
474 * NULL.
475 * if !dregs then rounding is performed instead of dithering.
476 * dregs are not freed.
477 * bottom dregs are placed back into dregs.
478 * Before return the bitmap will be in registered state and changes will be
479 * commited.
480 * height must be >=1 !!!
481 */
buffer_to_bitmap_incremental(struct cached_image * cimg,unsigned char * buffer,ssize_t height,ssize_t yoff,int * dregs,int use_strip)482 void buffer_to_bitmap_incremental(struct cached_image *cimg,
483 unsigned char *buffer, ssize_t height, ssize_t yoff, int *dregs, int use_strip)
484 {
485 #define max_height 16
486 /* max_height must be at least 1 */
487 unsigned short *tmp;
488 struct bitmap tmpbmp;
489 ssize_t add1 = 0, add2;
490
491 #ifdef DEBUG
492 if (cimg->state!=12&&cimg->state!=14){
493 fprintf(stderr,"cimg->state=%d\n",cimg->state);
494 internal_error("Invalid state in buffer_to_bitmap_incremental\n");
495 }
496 if (height<1){
497 fprintf(stderr,"height=%ld\n", (long)height);
498 internal_error("Invalid height in buffer_to_bitmap_incremental\n");
499 }
500 if (cimg->width<1||cimg->height<1){
501 fprintf(stderr,"cimg->width=%ld, cimg->height=%ld\n", (long)cimg->width, (long)cimg->height);
502 internal_error("Invalid cimg->width x cimg->height in\
503 buffer_to_bitmap_incremental");
504 }
505 #endif /* #ifdef DEBUG */
506 if ((size_t)cimg->width > MAX_SIZE_T / (size_t)max_height / 3 / sizeof(*tmp)) overalloc();
507 tmp=mem_alloc((size_t)cimg->width * (size_t)(height < max_height ? height : max_height) * 3 * sizeof(*tmp));
508 /* Prepare a fake bitmap for dithering */
509 tmpbmp.x = (int)cimg->width;
510 if (!use_strip){
511 tmpbmp.data=(unsigned char *)cimg->bmp.data+cimg->bmp.skip*yoff;
512 add1=cimg->bmp.skip*max_height;
513 }
514 add2=cimg->buffer_bytes_per_pixel*cimg->width*max_height;
515 not_enough:
516 tmpbmp.y = (int)(height < max_height ? height : max_height);
517 if (use_strip) {
518 tmpbmp.data = drv->prepare_strip(&(cimg->bmp), (int)yoff, tmpbmp.y);
519 if (!tmpbmp.data) goto prepare_failed;
520 }
521 tmpbmp.skip=cimg->bmp.skip;
522 buffer_to_16(tmp, cimg, buffer, tmpbmp.y);
523 if (dregs) {
524 dither_restart(tmp, &tmpbmp, dregs);
525 } else {
526 (*round_fn)(tmp, &tmpbmp);
527 }
528 if (use_strip) {
529 prepare_failed:
530 drv->commit_strip(&(cimg->bmp), (int)yoff, tmpbmp.y);
531 }
532 height-=tmpbmp.y;
533 if (!height) goto end;
534 buffer+=add2;
535 yoff+=tmpbmp.y;
536 tmpbmp.data=(unsigned char *)tmpbmp.data+add1;
537 /* This has no effect if use_strip but it's faster
538 * to add to bogus value than to play with
539 * conditional jumps.
540 */
541 goto not_enough;
542 end:
543 mem_free(tmp);
544 if (!use_strip) drv->register_bitmap(&(cimg->bmp));
545 }
546
547 /* Takes the buffer and resamples the data into the bitmap. Automatically
548 * destroys the previous bitmap. Must be called only when cimg->buffer is valid.
549 * Sets bmp_used to non-zero.
550 * If gamma_table is used, it must be still allocated here (take care if you
551 * want to destroy gamma table and call buffer_to_bitmap, first call buffer_to_bitmap
552 * and then destroy gamma_table).
553 */
buffer_to_bitmap(struct cached_image * cimg)554 static void buffer_to_bitmap(struct cached_image *cimg)
555 {
556 unsigned short *tmp, *tmp1;
557 ssize_t ix, iy, ox, oy;
558 int gonna_be_smart;
559 int *dregs;
560
561 #ifdef DEBUG
562 if(cimg->state!=12&&cimg->state!=14){
563 fprintf(stderr,"cimg->state=%d\n",cimg->state);
564 internal_error("buffer_to_bitmap called in invalid state");
565 }
566 if (cimg->strip_optimized) internal_error("strip_optimized in buffer_to_bitmap");
567 if (cimg->width<1||cimg->height<1){
568 fprintf(stderr,"cimg->width=%ld, cimg->height=%ld\n", (long)cimg->width, (long)cimg->height);
569 internal_error("Invalid cimg->width x cimg->height in buffer_to_bitmap");
570 }
571 #endif /* #ifdef DEBUG */
572
573
574 if (!cimg->rows_added) return;
575
576 /* Here of course width and height must be already filled */
577 cimg->rows_added=0;
578 ix=cimg->width;
579 iy=cimg->height;
580 ox=cimg->xww;
581 oy=cimg->yww;
582 if (ix==ox&&iy==oy) gonna_be_smart=1;
583 else{
584 gonna_be_smart=0;
585 if (ix && (size_t)ix * (size_t)iy / (size_t)ix != (size_t)iy) overalloc();
586 if ((size_t)ix * (size_t)iy > MAX_SIZE_T / sizeof(*tmp) / 3) overalloc();
587 tmp = mem_alloc_mayfail((size_t)ix * (size_t)iy * 3 * sizeof(*tmp));
588 if (tmp) buffer_to_16(tmp, cimg, cimg->buffer, iy);
589 if (!cimg->decoder){
590 mem_free_buffer(cimg);
591 cimg->buffer=NULL;
592 }
593
594 /* Scale the image to said size */
595 #ifdef DEBUG
596 if (ox<=0||oy<=0){
597 internal_error("ox or oy <=0 before resampling image");
598 }
599 #endif /* #ifdef DEBUG */
600 if (tmp && (ix!=ox || iy!=oy)) {
601 /* We must really scale */
602 tmp1=tmp;
603 scale_color(tmp1,ix,iy,&tmp,ox,oy);
604 }
605 }
606 if (cimg->bmp_used) drv->unregister_bitmap(&cimg->bmp);
607 cimg->bmp.x = (int)ox;
608 cimg->bmp.y = (int)oy;
609 if (drv->get_empty_bitmap(&(cimg->bmp))) {
610 if (!gonna_be_smart) {
611 if (tmp) {
612 mem_free(tmp);
613 }
614 }
615 goto bitmap_failed;
616 }
617 if (gonna_be_smart){
618 if (dither_images) {
619 if ((size_t)cimg->width > MAX_SIZE_T / 3 / sizeof(*dregs)) overalloc();
620 dregs = mem_calloc(sizeof(*dregs) * 3 * (size_t)cimg->width);
621 } else {
622 dregs = NULL;
623 }
624 buffer_to_bitmap_incremental(cimg, cimg->buffer, cimg->height,
625 0, dregs, 0);
626 if (dregs) mem_free(dregs);
627 }else{
628 if (tmp) {
629 if (dither_images)
630 dither(tmp, &cimg->bmp);
631 else
632 (*round_fn)(tmp, &cimg->bmp);
633 mem_free(tmp);
634 } else {
635 int i;
636 unsigned char *ptr = cimg->bmp.data;
637 for (i = 0; i < cimg->bmp.y; i++) {
638 memset(ptr, 0, cimg->bmp.x * (drv->depth & 7));
639 ptr += cimg->bmp.skip;
640 }
641 }
642 bitmap_failed:
643 drv->register_bitmap(&(cimg->bmp));
644 }
645 cimg->bmp_used=1;
646 /* Indicate that the bitmap is valid. The value is just any
647 nonzero value */
648 cimg->rows_added=0;
649 /* Indicate the bitmap is up-to-date */
650 }
651
652 /* Performs state transition for end of stream or error in image or
653 * end of image */
img_end(struct cached_image * cimg)654 void img_end(struct cached_image *cimg)
655 {
656 switch(cimg->state){
657 case 12:
658 case 14:
659 if (cimg->strip_optimized){
660 if (cimg->dregs) mem_free(cimg->dregs);
661 }
662 else{
663 buffer_to_bitmap(cimg);
664 mem_free_buffer(cimg);
665 }
666 if (cimg->gamma_table) mem_free(cimg->gamma_table);
667 /*-fallthrough*/
668 case 8:
669 case 10:
670 destroy_decoder(cimg);
671 case 0:
672 case 1:
673 case 2:
674 case 3:
675 case 9:
676 case 11:
677 case 13:
678 case 15:
679 break;
680 #ifdef DEBUG
681 default:
682 fprintf(stderr,"state=%d\n",cimg->state);
683 internal_error("Invalid state encountered in end");
684 #endif /* #ifdef DEBUG */
685 }
686 cimg->state|=1;
687 }
688
r3l0ad(struct cached_image * cimg,struct g_object_image * goi)689 static void r3l0ad(struct cached_image *cimg, struct g_object_image *goi)
690 {
691 cimg->eof_hit=0;
692 cimg->last_count=goi->af->rq->ce->count;
693 cimg->last_count2=goi->af->rq->ce->count2;
694 cimg->gamma_stamp=gamma_stamp;
695 switch(cimg->state){
696 case 8:
697 case 10:
698 destroy_decoder(cimg);
699 case 1:
700 case 3:
701 case 9:
702 case 11:
703 case 0:
704 case 2:
705 break;
706
707 case 12:
708 if (cimg->gamma_table) mem_free(cimg->gamma_table);
709 destroy_decoder(cimg);
710 if (cimg->strip_optimized){
711 if (cimg->dregs) mem_free(cimg->dregs);
712 }else{
713 mem_free_buffer(cimg);
714 }
715 if (cimg->bmp_used){
716 case 13:
717 drv->unregister_bitmap(&cimg->bmp);
718 }
719 cimg->xww=img_scale_h(cimg->scale, cimg->wanted_xw<0?32:cimg->wanted_xw);
720 cimg->yww=img_scale_v(cimg->scale, cimg->wanted_yw<0?32:cimg->wanted_yw);
721 break;
722
723 case 14:
724 if (cimg->gamma_table) mem_free(cimg->gamma_table);
725 destroy_decoder(cimg);
726 if (cimg->strip_optimized){
727 if (cimg->dregs) mem_free(cimg->dregs);
728 }else{
729 mem_free_buffer(cimg);
730 }
731 if (cimg->bmp_used){
732 case 15:
733 drv->unregister_bitmap(&cimg->bmp);
734 }
735 break;
736
737 #ifdef DEBUG
738 default:
739 fprintf(stderr,"cimg->state=%d\n",cimg->state);
740 internal_error("Invalid state in r3l0ad()");
741 #endif /* #ifdef DEBUG */
742 }
743 cimg->state&=2;
744 }
745
746 /* Returns 1 if match.
747 * If doesn't return 1 then returns 0
748 */
dtest(unsigned char * templat,unsigned char * test)749 static inline int dtest(unsigned char *templat, unsigned char *test)
750 {
751 return !casestrcmp(templat, test);
752 }
753
754 /* This may be called only in state 0 or 2 */
type(struct cached_image * cimg,unsigned char * content_type,unsigned char * data)755 static void type(struct cached_image *cimg, unsigned char *content_type, unsigned char *data /* at least 4 bytes */)
756 {
757 #ifdef DEBUG
758 if (cimg->state!=0&&cimg->state!=2){
759 fprintf(stderr,"cimg->state=%d\n",cimg->state);
760 internal_error("Invalid state encountered in type()");
761 }
762 #endif /* #ifdef DEBUG */
763 #ifdef HAVE_JPEG
764 if (data[0] == 0xff && data[1] == 0xd8)
765 goto have_jpeg;
766 #endif
767 #ifdef HAVE_TIFF
768 if (data[0] == 'I' && data[1] == 'I')
769 goto have_tiff;
770 if (data[0] == 'M' && data[1] == 'M')
771 goto have_tiff;
772 #endif
773 #ifdef HAVE_SVG
774 if (data[0] == '<' && data[1] == '?')
775 goto have_svg;
776 #endif
777 if (data[0] == 0x89 && data[1] == 'P' && data[2] == 'N' && data[3] == 'G')
778 goto have_png;
779 if (data[0] == 'G' && data[1] == 'I' && data[2] == 'F')
780 goto have_gif;
781 #ifdef HAVE_JPEG
782 if (dtest(cast_uchar "image/jpeg",content_type) ||
783 dtest(cast_uchar "image/jpg",content_type) ||
784 dtest(cast_uchar "image/jpe",content_type) ||
785 dtest(cast_uchar "image/pjpe",content_type) ||
786 dtest(cast_uchar "image/pjpeg",content_type) ||
787 dtest(cast_uchar "image/pjpg",content_type)) {
788 have_jpeg:
789 cimg->image_type=IM_JPG;
790 jpeg_start(cimg);
791 } else
792 #endif /* #ifdef HAVE_JPEG */
793 if (dtest(cast_uchar "image/png",content_type) ||
794 dtest(cast_uchar "image/x-png",content_type)) {
795 have_png:
796 cimg->image_type=IM_PNG;
797 png_start(cimg);
798 } else if (dtest(cast_uchar "image/gif",content_type)){
799 have_gif:
800 cimg->image_type=IM_GIF;
801 gif_start(cimg);
802 } else if (dtest(cast_uchar "image/x-xbitmap",content_type)){
803 cimg->image_type=IM_XBM;
804 xbm_start(cimg);
805 } else
806 #ifdef HAVE_TIFF
807 if (dtest(cast_uchar "image/tiff",content_type) ||
808 dtest(cast_uchar "image/tif",content_type)) {
809 have_tiff:
810 cimg->image_type=IM_TIFF;
811 tiff_start(cimg);
812 } else
813 #endif /* #ifdef HAVE_TIFF */
814 #ifdef HAVE_SVG
815 if (dtest(cast_uchar "image/svg+xml",content_type) ||
816 dtest(cast_uchar "image/svg",content_type)) {
817 have_svg:
818 cimg->image_type=IM_SVG;
819 svg_start(cimg);
820 } else
821 #endif /* #ifdef HAVE_SVG */
822 {
823 /* Error */
824 img_end(cimg);
825 return;
826 }
827 cimg->state|=8; /* Advance the state according to the table in
828 links-doc.html */
829 cimg->last_length=0;
830 }
831
832 /* Doesn't print anything. Downloads more data if available.
833 * Sets up cimg->reparse and cimg->xww and cimg->yww accordingly to
834 * the state of the decoder. When changing xww and yww also changes xw and yw
835 * in g_object_image.
836 * return value 1 means the data were chopped and the caller shall not redraw
837 * (because it would be too slow and because we are probably choked
838 * up with the data)
839 */
img_process_download(struct g_object_image * goi,struct f_data_c * fdatac)840 static int img_process_download(struct g_object_image *goi, struct f_data_c *fdatac)
841 {
842 unsigned char *data, *ctype;
843 size_t total_len;
844 struct cached_image *cimg = goi->cimg;
845 int chopped=0;
846
847 #ifdef DEBUG
848 if (!goi->af) internal_error("NULL goi->af in process_download\n");
849 if (cimg->state>=16){ /* Negative don't occur because it's unsigned char */
850 fprintf(stderr,"cimg->state=%d\n",cimg->state);
851 internal_error("Invalid cimg->state in img_process_download\n");
852 }
853 #endif /* #ifdef DEBUG */
854 if (!goi->af->rq) return 0;
855 if (get_file(goi->af->rq, &data, &total_len)) goto end;
856 if (total_len < 4) goto end;
857 if (total_len > MAXINT) total_len = MAXINT;
858 /*fprintf(stderr, "processing: %s\n", goi->af->rq->ce->url);*/
859 if (goi->af->rq->ce->count2!=cimg->last_count2||
860 (goi->af->rq->ce->count!=cimg->last_count && cimg->eof_hit) ||
861 (cimg->state>=12&&gamma_stamp!=cimg->gamma_stamp)){
862 /* Reload */
863 r3l0ad(cimg,goi);
864 }
865 /*if (!goi->af->rq->ce->head) goto end;*/ /* Mikulas: head muze byt NULL*/ /* Mikulas: tak se to zpracuje a nebude se skakat na konec, kdyz je to NULL */
866
867 if (cimg->state==0||cimg->state==2){
868 /* Type still unknown */
869 ctype=get_content_type(goi->af->rq->ce->head,
870 goi->af->rq->url);
871 if (!ctype) ctype = stracpy(cast_uchar "application/octet-stream");
872 type(cimg,ctype,data);
873 mem_free(ctype);
874 }
875
876 /* Now, if we are in state where decoder is running (8, 10, 12, 14), we may feed
877 * some data into it.
878 */
879
880 if (!((cimg->state^8)&9)){
881 int length = (int)total_len;
882 if (length<=cimg->last_length) goto end; /* No new data */
883
884 data+=cimg->last_length;
885 length-=cimg->last_length;
886 if (length>RESTART_SIZE){
887 length=RESTART_SIZE;
888 chopped=1;
889 if (fdatac) {
890 refresh_image(fdatac, &goi->goti.go, 0);
891 }
892 }
893 /* Decoder has been already started */
894 switch(cimg->image_type){
895 case IM_PNG:
896 png_restart(cimg,data,length);
897 break;
898 #ifdef HAVE_JPEG
899 case IM_JPG:
900 jpeg_restart(cimg,data,length);
901 break;
902 #endif /* #ifdef HAVE_JPEG */
903 case IM_XBM:
904 xbm_restart(cimg,data,length);
905 break;
906 case IM_GIF:
907 gif_restart(data,length);
908 break;
909 #ifdef HAVE_TIFF
910 case IM_TIFF:
911 tiff_restart(cimg,data,length);
912 break;
913 #endif /* #ifdef HAVE_TIFF */
914 #ifdef HAVE_SVG
915 case IM_SVG:
916 svg_restart(cimg,data,length);
917 break;
918 #endif /* #ifdef HAVE_SVG */
919 #ifdef DEBUG
920 default:
921 fprintf(stderr,"cimg->image_type=%d\n",cimg->state);
922 internal_error("Invalid image_type encountered when processing data in\
923 img_process_download.\n");
924 #endif /* #ifdef DEBUG */
925 }
926 cimg->last_length+=length;
927 }
928 end:
929
930 /* Test end */
931 if (!is_entry_used(goi->af->rq->ce) && (goi->af->rq->state < 0
932 ||(goi->af->rq->ce&&goi->af->rq->stat.state<0))){
933 /* We must not perform end with chopped because some
934 * unprocessed data still wait for us :)
935 */
936 if (!chopped){
937 if (!((cimg->state^8)&9)) {
938 #ifdef HAVE_TIFF
939 if (cimg->image_type==IM_TIFF)
940 tiff_finish(cimg);
941 #endif
942 #ifdef HAVE_SVG
943 if (cimg->image_type==IM_SVG)
944 svg_finish(cimg);
945 #endif
946 }
947 cimg->eof_hit=1;
948 if (goi->af->rq->ce)
949 cimg->last_count=goi->af->rq->ce->count;
950 img_end(cimg);
951 }
952 } else if (!chopped) {
953 if (fdatac) {
954 if (f_is_finished(fdatac->f_data)) {
955 refresh_image(fdatac, &goi->goti.go, 2000);
956 } else {
957 /*
958 * Fix a bug - if we have a text file with html and built-in image using
959 * the data:// url. If we press '\' to toggle the view from text to
960 * html, the image is not displayed correctly. We need to reset
961 * fdatac->done to force re-parse.
962 */
963 fdatac->done = 0;
964 }
965 }
966 }
967 return chopped;
968 }
969
970 /* Input: rgb (sRGB) triplet (0...255)
971 * Returns a color that is very contrasty on that background sRGB color
972 */
get_foreground(int rgb)973 int get_foreground(int rgb)
974 {
975 int r,g,b;
976
977 r=(rgb>>16)&255;
978 g=(rgb>>8)&255;
979 b=rgb&255;
980
981 r=r<128?255:0;
982 g=g<128?255:0;
983 b=b<128?255:0;
984
985 return (r<<16)|(g<<8)|b;
986 }
987
draw_frame_mark(struct graphics_device * dev,int x,int y,int xw,int yw,long bg,long fg,int broken)988 static void draw_frame_mark(struct graphics_device *dev, int x, int y, int xw, int yw, long bg, long fg, int broken)
989 {
990 #ifdef DEBUG
991 if (xw<1||yw<1) internal_error("zero dimension in draw_frame_mark");
992 #endif /* #ifdef DEBUG */
993 if (broken == 1){
994 /* Draw between ( 0 and 1/4 ) and ( 3/4 and 1 ) of each
995 * side (0-1)
996 */
997 int xl, xh, yl, yh;
998
999 xh=xw-(xl=xw>>2);
1000 yh=yw-(yl=yw>>2);
1001 /* Draw full sides and the box inside */
1002 drv->draw_hline(dev,x,y,x+xl,fg);
1003 drv->draw_hline(dev,x+xl,y,x+xh,bg);
1004 drv->draw_hline(dev,x+xh,y,x+xw,fg);
1005 if (yw>=1){
1006 if (yw>=2){
1007 drv->draw_vline(dev,x,y+1,y+yl,fg);
1008 drv->draw_vline(dev,x,y+yl,y+yh,bg);
1009 drv->draw_vline(dev,x,y+yh,y+yw-1,fg);
1010 if (xw>=1){
1011 if (xw>=2){
1012 drv->fill_area(dev,
1013 x+1,y+1,x+xw-1,y+yw-1,
1014 bg);
1015 }
1016 drv->draw_vline(dev,x+xw-1,y+1,y+yl,fg);
1017 drv->draw_vline(dev,x+xw-1,y+yl,y+yh,bg);
1018 drv->draw_vline(dev,x+xw-1,y+yh,y+yw-1,fg);
1019 }
1020 }
1021 drv->draw_hline(dev,x,y+yw-1,x+xl,fg);
1022 drv->draw_hline(dev,x+xl,y+yw-1,x+xh,bg);
1023 drv->draw_hline(dev,x+xh,y+yw-1,x+xw,fg);
1024 }
1025 }else {
1026 /* Draw full sides and the box inside */
1027 drv->draw_hline(dev,x,y,x+xw,fg);
1028 if (yw>=1){
1029 if (yw>=2){
1030 drv->draw_vline(dev,x,y+1,y+yw-1,fg);
1031 if (xw>=1){
1032 if (xw>=2){
1033 if (broken < 2) drv->fill_area(dev,
1034 x+1,y+1,x+xw-1,y+yw-1,
1035 bg);
1036 }
1037 drv->draw_vline(dev,x+xw-1,y+1,
1038 y+yw-1,fg);
1039 }
1040 }
1041 drv->draw_hline(dev,x,y+yw-1,x+xw,fg);
1042 }
1043 if (broken == 2 && xw > 2 && yw > 2) {
1044 draw_frame_mark(dev, x + 1, y + 1, xw - 2, yw - 2, bg, fg, 3);
1045 }
1046 }
1047 }
1048
image_backgronud(struct cached_image * cimg)1049 static long image_backgronud(struct cached_image *cimg)
1050 {
1051 if (!cimg) return dip_get_color_sRGB(0x00c0c0c0);
1052 return dip_get_color_sRGB(cimg->background_color);
1053 }
1054
image_foregronud(struct cached_image * cimg)1055 static long image_foregronud(struct cached_image *cimg)
1056 {
1057 if (!cimg) return dip_get_color_sRGB(0x00000000);
1058 return dip_get_color_sRGB(get_foreground(cimg->background_color));
1059 }
1060
1061 /* Entry is allowed only in states 12, 13, 14, 15
1062 * Draws the picture from bitmap.
1063 * Before doing so, ensures that bitmap is present and if not, converts it from
1064 * the buffer.
1065 */
draw_picture(struct f_data_c * fdatac,struct g_object_image * goi,int x,int y)1066 static void draw_picture(struct f_data_c *fdatac, struct g_object_image *goi, int x, int y)
1067 {
1068 struct graphics_device *dev = fdatac->ses->term->dev;
1069 struct cached_image *cimg = goi->cimg;
1070 struct rect saved;
1071
1072 #ifdef DEBUG
1073 if (goi->cimg->state < 12 || goi->cimg->state >= 16) {
1074 fprintf(stderr, "cimg->state=%d\n", cimg->state);
1075 internal_error("Invalid cimg->state in draw_picture");
1076 }
1077 #endif /* #ifdef DEBUG */
1078 if (!(cimg->state & 1)) {
1079 if (!cimg->bmp_used)
1080 buffer_to_bitmap(cimg);
1081 }
1082 #ifdef DEBUG
1083 else if (!cimg->bmp_used) {
1084 fprintf(stderr, "cimg->state=%d\n", cimg->state);
1085 internal_error("Nonexistent bitmap in said cimg->state in draw_picture");
1086 }
1087 #endif /* #ifdef DEBUG */
1088 restrict_clip_area(dev, &saved, x, y, x + goi->goti.go.xw, y + goi->goti.go.yw);
1089 drv->draw_bitmap(dev, &cimg->bmp, x, y);
1090 if (cimg->bmp.x < goi->goti.go.xw ||
1091 cimg->bmp.y < goi->goti.go.yw) {
1092 long bg = image_backgronud(cimg);
1093 drv->fill_area(dev, x + cimg->bmp.x, y, x + goi->goti.go.xw, y + cimg->bmp.y, bg);
1094 drv->fill_area(dev, x, y + cimg->bmp.y, x + goi->goti.go.xw, y + goi->goti.go.yw, bg);
1095 }
1096 set_clip_area(dev, &saved);
1097 }
1098
1099 /* Ensures in buffer there is not newer picture than in bitmap. Allowed to be
1100 * called only in state 12, 13, 14, 15.
1101 */
update_bitmap(struct cached_image * cimg)1102 static void update_bitmap(struct cached_image *cimg)
1103 {
1104 #ifdef DEBUG
1105 if (cimg->state < 12 || cimg->state >= 16) {
1106 fprintf(stderr, "cimg->state=%d\n", cimg->state);
1107 internal_error("Invalid state in update_bitmap");
1108 }
1109 #endif /* #ifdef DEBUG */
1110 if (!(cimg->state & 1) && !cimg->strip_optimized && cimg->rows_added)
1111 buffer_to_bitmap(cimg);
1112 }
1113
1114 /* Draws the image at x,y. Is called from other C sources. */
img_draw_image(struct f_data_c * fdatac,struct g_object * goi_,int x,int y)1115 static void img_draw_image(struct f_data_c *fdatac, struct g_object *goi_, int x, int y)
1116 {
1117 struct g_object_image *goi = get_struct(goi_, struct g_object_image, goti.go);
1118 struct cached_image *cimg = goi->cimg;
1119 struct rect r;
1120 /* refresh_image(fdatac, goi, 1000); To sem asi napsal mikulas jako
1121 * navod, jak se vola to refresh_image. Nicmene ja jsem milostive
1122 * usoudil, ze zadnejch 1000, ale 0.
1123 */
1124
1125 if (!(goi->goti.go.xw && goi->goti.go.yw))
1126 return; /* At least one dimension is zero */
1127
1128 memcpy(&r, &fdatac->ses->term->dev->clip, sizeof(struct rect));
1129 if (fdatac->vs->g_display_link && fdatac->active && fdatac->vs->current_link != -1 && fdatac->vs->current_link == goi->goti.link_num) {
1130 long fg = image_foregronud(cimg);
1131 draw_frame_mark(fdatac->ses->term->dev, x, y, goi->goti.go.xw,
1132 goi->goti.go.yw, fg, fg, 2);
1133 restrict_clip_area(fdatac->ses->term->dev, &r, x + 2, y + 2, x + goi->goti.go.xw - 2, y + goi->goti.go.yw - 2);
1134 }
1135
1136 global_goi=goi;
1137 global_cimg=goi->cimg;
1138 if (img_process_download(goi, fdatac)) goto ret; /* Choked with data, will not
1139 * draw. */
1140 /* Now we will only draw... */
1141 if (!cimg || cimg->state < 12) {
1142 long fg = image_foregronud(cimg);
1143 long bg = image_backgronud(cimg);
1144 draw_frame_mark(fdatac->ses->term->dev, x, y, goi->goti.go.xw,
1145 goi->goti.go.yw, bg, fg, !cimg || cimg->state & 1);
1146 } else {
1147 #ifdef DEBUG
1148 if (cimg->state >= 16)
1149 internal_error("Invalid state in img_draw_image: %d", cimg->state);
1150 #endif
1151 update_bitmap(cimg);
1152 draw_picture(fdatac, goi, x, y);
1153 }
1154 ret:
1155 set_clip_area(fdatac->ses->term->dev, &r);
1156 #ifdef LINKS_TESTMODE_IMAGE_AUTO_EXIT
1157 if (cimg->state & 1)
1158 terminate_loop = 1;
1159 #endif
1160 }
1161
1162 /* Prior to calling this function you have to fill out
1163 * image -> xw (<0 means not known)
1164 * image -> yw (<0 means not known)
1165 * image -> xyw meaning (MEANING_AUTOSCALE or MEANING_DIMS)
1166 * image -> background
1167 *
1168 * The URL will not be freed.
1169 */
find_or_make_cached_image(struct g_object_image * image,unsigned char * url,int scale)1170 static void find_or_make_cached_image(struct g_object_image *image, unsigned char *url,
1171 int scale)
1172 {
1173 struct cached_image *cimg;
1174
1175 if (!(cimg = find_cached_image(image->background, url, image->goti.go.xw,
1176 image->goti.go.yw, image->xyw_meaning, scale, aspect))){
1177 /* We have to make a new image cache entry */
1178 cimg = mem_alloc(sizeof(*cimg));
1179 cimg->background_color = image->background;
1180 #ifdef DEBUG
1181 if (!url)
1182 internal_error("NULL url as argument of\
1183 find_or_make_cached_image");
1184 #endif /* #ifdef DEBUG */
1185 cimg->scale = scale;
1186 cimg->aspect = aspect;
1187 cimg->url = stracpy(url);
1188 cimg->wanted_xw = image->goti.go.xw;
1189 cimg->wanted_yw = image->goti.go.yw;
1190 cimg->wanted_xyw_meaning = image->xyw_meaning;
1191 cimg->xww = image->goti.go.xw < 0 ? img_scale_h(cimg->scale, 32) : cimg->wanted_xw;
1192 cimg->yww = image->goti.go.yw < 0 ? img_scale_v(cimg->scale, 32) : cimg->wanted_yw;
1193 cimg->state=0;
1194 /* width, height, image_type, buffer, buffer_bytes_per_pixel, red_gamma,
1195 * green_gamma, blue_gamma, gamma_stamp, bitmap, last_length, rows_added,
1196 * and decoder is invalid in both state 0 and state 2. Thus is need no to
1197 * be filled in.
1198 */
1199
1200 /* last_count2 is unitialized */
1201 cimg->eof_hit = 0;
1202 cimg->last_count = -1;
1203 cimg->last_count2 = -1;
1204 if (cimg->wanted_xw >= 0 && cimg->wanted_yw >=0) cimg->state |= 2;
1205 add_image_to_cache(cimg);
1206 }
1207 global_cimg = image->cimg = cimg;
1208 }
1209
1210 /* The original (unscaled, in pixels pace) size is requested in im->xsize and im->ysize.
1211 * <0 means unknown. Autoscale is requested in autoscale. When autoscale is on,
1212 * the requested dimensions are not scaled and they mean maximum allowed
1213 * dimensions. */
insert_image(struct g_part * p,struct image_description * im)1214 struct g_object_image *insert_image(struct g_part *p, struct image_description *im)
1215 {
1216 struct g_object_image *image;
1217 struct cached_image *cimg;
1218 int retval;
1219 ssize_t xw, yw;
1220
1221 image=mem_calloc(sizeof(struct g_object_image));
1222 global_goi = image;
1223 image->goti.go.mouse_event = g_text_mouse;
1224 image->goti.go.draw = img_draw_image;
1225 image->goti.go.destruct = img_destruct_image;
1226 image->goti.go.get_list = NULL;
1227 image->goti.link_num = im->link_num;
1228 image->goti.link_order = im->link_order;
1229 image->goti.map = NULL;
1230 /*
1231 image->goti.go.x is already filled
1232 image->goti.go.y is already filled
1233 */
1234 if (im->align == AL_MIDDLE) image->goti.go.y = G_OBJ_ALIGN_MIDDLE;
1235 if (im->align == AL_TOP) image->goti.go.y = G_OBJ_ALIGN_TOP;
1236
1237 if (im->autoscale_x && im->autoscale_y) {
1238 /* Autoscale requested */
1239 xw = im->autoscale_x;
1240 yw = im->autoscale_y;
1241 image->goti.go.xw = (int)xw;
1242 image->goti.go.yw = (int)yw;
1243 image->xyw_meaning = MEANING_AUTOSCALE;
1244 }else{
1245 /* Autoscale not requested */
1246 xw = img_scale_h(d_opt->image_scale, im->xsize);
1247 yw = img_scale_v(d_opt->image_scale, im->ysize);
1248 image->goti.go.xw = (int)xw;
1249 image->goti.go.yw = (int)yw;
1250 image->xyw_meaning = MEANING_DIMS;
1251 }
1252 if (xw >= 0 && yw >= 0) {
1253 if (!is_image_size_sane(xw, yw)) {
1254 mem_free(image);
1255 return NULL;
1256 }
1257 }
1258
1259 /* Put the data for javascript inside */
1260 image->id = current_f_data->n_images++;
1261 image->name = stracpy(im->name);
1262 image->alt = stracpy(im->alt);
1263 image->orig_src = stracpy(im->src);
1264 image->border = im->border;
1265 image->vspace = im->vspace;
1266 image->hspace = im->hspace;
1267 image->src = stracpy(im->url);
1268
1269 if (!(image->goti.go.xw && image->goti.go.yw)) {
1270 /* At least one is zero */
1271 if (image->goti.go.xw < 0) image->goti.go.xw = 0;
1272 if (image->goti.go.yw < 0) image->goti.go.yw = 0;
1273 if (im->insert_flag) add_to_list(current_f_data->images, image);
1274 else image->list_entry.prev = image->list_entry.next = NULL;
1275 return image;
1276 }
1277 /*
1278 image->parent is already filled
1279 */
1280 image->af = request_additional_file(current_f_data, im->url);
1281 if (image->goti.go.xw < 0 || image->goti.go.yw < 0) image->af->unknown_image_size = 1;
1282 image->background = hack_rgb(p->root->bg->sRGB);
1283
1284 /* This supplies the result into image->cimg and global_cimg */
1285 find_or_make_cached_image(image, im->url, d_opt->image_scale);
1286 cimg = global_cimg;
1287
1288 next_chunk:
1289 retval = img_process_download(image, NULL);
1290 if (retval && !(cimg->state & 4)) goto next_chunk;
1291 image->goti.go.xw = (int)image->cimg->xww;
1292 image->goti.go.yw = (int)image->cimg->yww;
1293 if (cimg->state == 0 || cimg->state == 8 || image->af->unknown_image_size) if (image->af->need_reparse != -1) image->af->need_reparse = 1;
1294 if (im->insert_flag) add_to_list(current_f_data->images, image);
1295 else image->list_entry.prev = image->list_entry.next = NULL;
1296 return image;
1297 }
1298
1299 #ifdef JS
1300
change_image(struct g_object_image * goi,unsigned char * url,unsigned char * src,struct f_data * fdata)1301 void change_image (struct g_object_image *goi, unsigned char *url, unsigned char *src, struct f_data *fdata)
1302 {
1303 /*struct cached_image *cimg;*/
1304
1305 global_goi = goi;
1306 mem_free(goi->src);
1307 goi->src = stracpy(url);
1308 if (goi->orig_src) mem_free(goi->orig_src);
1309 goi->orig_src = stracpy(src);
1310 if (!(goi->goti.go.xw && goi->goti.go.yw)) return;
1311 deref_cached_image(goi->cimg);
1312 goi->af = request_additional_file(fdata, url);
1313 goi->af->need_reparse = -1;
1314
1315 find_or_make_cached_image(goi, url, fdata->opt.image_scale);
1316 /* Automatically sets up global_cimg */
1317
1318 refresh_image(fdata->fd, &goi->goti.go, 0);
1319 }
1320
1321 #endif
1322
1323 #endif
1324
known_image_type(unsigned char * type)1325 int known_image_type(unsigned char *type)
1326 {
1327 #ifdef G
1328 if (!casestrcmp(type, cast_uchar "image/png")) return 1;
1329 if (!casestrcmp(type, cast_uchar "image/x-png")) return 1;
1330 if (!casestrcmp(type, cast_uchar "image/gif")) return 1;
1331 if (!casestrcmp(type, cast_uchar "image/x-xbitmap")) return 1;
1332 #ifdef HAVE_JPEG
1333 if (!casestrcmp(type, cast_uchar "image/jpeg")) return 1;
1334 if (!casestrcmp(type, cast_uchar "image/jpg")) return 1;
1335 if (!casestrcmp(type, cast_uchar "image/jpe")) return 1;
1336 if (!casestrcmp(type, cast_uchar "image/pjpe")) return 1;
1337 if (!casestrcmp(type, cast_uchar "image/pjpeg")) return 1;
1338 if (!casestrcmp(type, cast_uchar "image/pjpg")) return 1;
1339 #endif
1340 #ifdef HAVE_TIFF
1341 if (!casestrcmp(type, cast_uchar "image/tiff")) return 1;
1342 if (!casestrcmp(type, cast_uchar "image/tif")) return 1;
1343 #endif
1344 #ifdef HAVE_SVG
1345 if (!casestrcmp(type, cast_uchar "image/svg+xml")) return 1;
1346 if (!casestrcmp(type, cast_uchar "image/svg")) return 1;
1347 #endif
1348 #endif
1349 return 0;
1350 }
1351