1 /*
2 * Base image support for CUPS.
3 *
4 * Copyright 2007-2011 by Apple Inc.
5 * Copyright 1993-2005 by Easy Software Products.
6 *
7 * These coded instructions, statements, and computer programs are the
8 * property of Apple Inc. and are protected by Federal copyright
9 * law. Distribution and use rights are outlined in the file "COPYING"
10 * which should have been included with this file.
11 *
12 * Contents:
13 *
14 * cupsImageClose() - Close an image file.
15 * cupsImageGetCol() - Get a column of pixels from an image.
16 * cupsImageGetColorSpace() - Get the image colorspace.
17 * cupsImageGetDepth() - Get the number of bytes per pixel.
18 * cupsImageGetHeight() - Get the height of an image.
19 * cupsImageGetRow() - Get a row of pixels from an image.
20 * cupsImageGetWidth() - Get the width of an image.
21 * cupsImageGetXPPI() - Get the horizontal resolution of an image.
22 * cupsImageGetYPPI() - Get the vertical resolution of an image.
23 * cupsImageOpen() - Open an image file and read it into memory.
24 * _cupsImagePutCol() - Put a column of pixels to an image.
25 * _cupsImagePutRow() - Put a row of pixels to an image.
26 * cupsImageSetMaxTiles() - Set the maximum number of tiles to cache.
27 * flush_tile() - Flush the least-recently-used tile in the cache.
28 * get_tile() - Get a cached tile.
29 * _cupsImageReadEXIF() - to read exif metadata of images
30 * trim_spaces() - helper function to extract results from string
31 * returned by exif library functions
32 * find_bytes() - creates character array from image file, to
33 * make use in exif library functions
34 */
35
36 /*
37 * Include necessary headers...
38 */
39
40
41 #include "image-private.h"
42
43
44 /*
45 * Local functions...
46 */
47
48 static int flush_tile(cups_image_t *img);
49 static cups_ib_t *get_tile(cups_image_t *img, int x, int y);
50 static void trim_spaces(char *buf);
51 static unsigned char *find_bytes(FILE *fp, long int *size);
52
53
54 /*
55 * 'cupsImageClose()' - Close an image file.
56 */
57
58 void
cupsImageClose(cups_image_t * img)59 cupsImageClose(cups_image_t *img) /* I - Image to close */
60 {
61 cups_ic_t *current, /* Current cached tile */
62 *next; /* Next cached tile */
63
64
65 /*
66 * Wipe the tile cache file (if any)...
67 */
68
69 if (img->cachefile >= 0)
70 {
71 DEBUG_printf(("Closing/removing swap file \"%s\"...\n", img->cachename));
72
73 close(img->cachefile);
74 unlink(img->cachename);
75 }
76
77 /*
78 * Free the image cache...
79 */
80
81 DEBUG_puts("Freeing memory...");
82
83 for (current = img->first, next = NULL; current != NULL; current = next)
84 {
85 DEBUG_printf(("Freeing cache (%p, next = %p)...\n", current, next));
86
87 next = current->next;
88 free(current);
89 }
90
91 /*
92 * Free the rest of memory...
93 */
94
95 if (img->tiles != NULL)
96 {
97 DEBUG_printf(("Freeing tiles (%p)...\n", img->tiles[0]));
98
99 free(img->tiles[0]);
100
101 DEBUG_printf(("Freeing tile pointers (%p)...\n", img->tiles));
102
103 free(img->tiles);
104 }
105
106 free(img);
107 }
108
109
110 /*
111 * 'cupsImageGetCol()' - Get a column of pixels from an image.
112 */
113
114 int /* O - -1 on error, 0 on success */
cupsImageGetCol(cups_image_t * img,int x,int y,int height,cups_ib_t * pixels)115 cupsImageGetCol(cups_image_t *img, /* I - Image */
116 int x, /* I - Column */
117 int y, /* I - Start row */
118 int height, /* I - Column height */
119 cups_ib_t *pixels) /* O - Pixel data */
120 {
121 int bpp, /* Bytes per pixel */
122 twidth, /* Tile width */
123 count; /* Number of pixels to get */
124 const cups_ib_t *ib; /* Pointer into tile */
125
126
127 if (img == NULL || x < 0 || x >= img->xsize || y >= img->ysize)
128 return (-1);
129
130 if (y < 0)
131 {
132 height += y;
133 y = 0;
134 }
135
136 if ((y + height) > img->ysize)
137 height = img->ysize - y;
138
139 if (height < 1)
140 return (-1);
141
142 bpp = cupsImageGetDepth(img);
143 twidth = bpp * (CUPS_TILE_SIZE - 1);
144
145 while (height > 0)
146 {
147 ib = get_tile(img, x, y);
148
149 if (ib == NULL)
150 return (-1);
151
152 count = CUPS_TILE_SIZE - (y & (CUPS_TILE_SIZE - 1));
153 if (count > height)
154 count = height;
155
156 y += count;
157 height -= count;
158
159 for (; count > 0; count --, ib += twidth)
160 switch (bpp)
161 {
162 case 4 :
163 *pixels++ = *ib++;
164 case 3 :
165 *pixels++ = *ib++;
166 *pixels++ = *ib++;
167 case 1 :
168 *pixels++ = *ib++;
169 break;
170 }
171 }
172
173 return (0);
174 }
175
176
177 /*
178 * 'cupsImageGetColorSpace()' - Get the image colorspace.
179 */
180
181 cups_icspace_t /* O - Colorspace */
cupsImageGetColorSpace(cups_image_t * img)182 cupsImageGetColorSpace(
183 cups_image_t *img) /* I - Image */
184 {
185 return (img->colorspace);
186 }
187
188
189 /*
190 * 'cupsImageGetDepth()' - Get the number of bytes per pixel.
191 */
192
193 int /* O - Bytes per pixel */
cupsImageGetDepth(cups_image_t * img)194 cupsImageGetDepth(cups_image_t *img) /* I - Image */
195 {
196 return (abs(img->colorspace));
197 }
198
199
200 /*
201 * 'cupsImageGetHeight()' - Get the height of an image.
202 */
203
204 unsigned /* O - Height in pixels */
cupsImageGetHeight(cups_image_t * img)205 cupsImageGetHeight(cups_image_t *img) /* I - Image */
206 {
207 return (img->ysize);
208 }
209
210
211 /*
212 * 'cupsImageGetRow()' - Get a row of pixels from an image.
213 */
214
215 int /* O - -1 on error, 0 on success */
cupsImageGetRow(cups_image_t * img,int x,int y,int width,cups_ib_t * pixels)216 cupsImageGetRow(cups_image_t *img, /* I - Image */
217 int x, /* I - Start column */
218 int y, /* I - Row */
219 int width, /* I - Width of row */
220 cups_ib_t *pixels) /* O - Pixel data */
221 {
222 int bpp, /* Bytes per pixel */
223 count; /* Number of pixels to get */
224 const cups_ib_t *ib; /* Pointer to pixels */
225
226
227 if (img == NULL || y < 0 || y >= img->ysize || x >= img->xsize)
228 return (-1);
229
230 if (x < 0)
231 {
232 width += x;
233 x = 0;
234 }
235
236 if ((x + width) > img->xsize)
237 width = img->xsize - x;
238
239 if (width < 1)
240 return (-1);
241
242 bpp = img->colorspace < 0 ? -img->colorspace : img->colorspace;
243
244 while (width > 0)
245 {
246 ib = get_tile(img, x, y);
247
248 if (ib == NULL)
249 return (-1);
250
251 count = CUPS_TILE_SIZE - (x & (CUPS_TILE_SIZE - 1));
252 if (count > width)
253 count = width;
254 memcpy(pixels, ib, count * bpp);
255 pixels += count * bpp;
256 x += count;
257 width -= count;
258 }
259
260 return (0);
261 }
262
263
264 /*
265 * 'cupsImageGetWidth()' - Get the width of an image.
266 */
267
268 unsigned /* O - Width in pixels */
cupsImageGetWidth(cups_image_t * img)269 cupsImageGetWidth(cups_image_t *img) /* I - Image */
270 {
271 return (img->xsize);
272 }
273
274
275 /*
276 * 'cupsImageGetXPPI()' - Get the horizontal resolution of an image.
277 */
278
279 unsigned /* O - Horizontal PPI */
cupsImageGetXPPI(cups_image_t * img)280 cupsImageGetXPPI(cups_image_t *img) /* I - Image */
281 {
282 return (img->xppi);
283 }
284
285
286 /*
287 * 'cupsImageGetYPPI()' - Get the vertical resolution of an image.
288 */
289
290 unsigned /* O - Vertical PPI */
cupsImageGetYPPI(cups_image_t * img)291 cupsImageGetYPPI(cups_image_t *img) /* I - Image */
292 {
293 return (img->yppi);
294 }
295
296
297 /*
298 * 'cupsImageOpen()' - Open an image file and read it into memory.
299 */
300
301 cups_image_t * /* O - New image */
cupsImageOpen(const char * filename,cups_icspace_t primary,cups_icspace_t secondary,int saturation,int hue,const cups_ib_t * lut)302 cupsImageOpen(
303 const char *filename, /* I - Filename of image */
304 cups_icspace_t primary, /* I - Primary colorspace needed */
305 cups_icspace_t secondary, /* I - Secondary colorspace if primary no good */
306 int saturation, /* I - Color saturation level */
307 int hue, /* I - Color hue adjustment */
308 const cups_ib_t *lut) /* I - RGB gamma/brightness LUT */
309 {
310 FILE *fp; /* File pointer */
311 unsigned char header[16], /* First 16 bytes of file */
312 header2[16]; /* Bytes 2048-2064 (PhotoCD) */
313 cups_image_t *img; /* New image buffer */
314 int status; /* Status of load... */
315
316
317 DEBUG_printf(("cupsImageOpen(\"%s\", %d, %d, %d, %d, %p)\n",
318 filename ? filename : "(null)", primary, secondary,
319 saturation, hue, lut));
320
321 /*
322 * Figure out the file type...
323 */
324
325 if ((fp = fopen(filename, "r")) == NULL)
326 return (NULL);
327
328 if (fread(header, 1, sizeof(header), fp) == 0)
329 {
330 fclose(fp);
331 return (NULL);
332 }
333
334 fseek(fp, 2048, SEEK_SET);
335 memset(header2, 0, sizeof(header2));
336 if (fread(header2, 1, sizeof(header2), fp) == 0 && ferror(fp))
337 DEBUG_printf(("Error reading file!"));
338 fseek(fp, 0, SEEK_SET);
339
340 /*
341 * Allocate memory...
342 */
343
344 img = calloc(sizeof(cups_image_t), 1);
345
346 if (img == NULL)
347 {
348 fclose(fp);
349 return (NULL);
350 }
351
352 /*
353 * Load the image as appropriate...
354 */
355
356 img->cachefile = -1;
357 img->max_ics = CUPS_TILE_MINIMUM;
358 img->xppi = 200;
359 img->yppi = 200;
360
361 if (!memcmp(header, "GIF87a", 6) || !memcmp(header, "GIF89a", 6))
362 status = _cupsImageReadGIF(img, fp, primary, secondary, saturation, hue,
363 lut);
364 else if (!memcmp(header, "BM", 2))
365 status = _cupsImageReadBMP(img, fp, primary, secondary, saturation, hue,
366 lut);
367 else if (header[0] == 0x01 && header[1] == 0xda)
368 status = _cupsImageReadSGI(img, fp, primary, secondary, saturation, hue,
369 lut);
370 else if (header[0] == 0x59 && header[1] == 0xa6 &&
371 header[2] == 0x6a && header[3] == 0x95)
372 status = _cupsImageReadSunRaster(img, fp, primary, secondary, saturation,
373 hue, lut);
374 else if (header[0] == 'P' && header[1] >= '1' && header[1] <= '6')
375 status = _cupsImageReadPNM(img, fp, primary, secondary, saturation, hue,
376 lut);
377 else if (!memcmp(header2, "PCD_IPI", 7))
378 status = _cupsImageReadPhotoCD(img, fp, primary, secondary, saturation,
379 hue, lut);
380 else if (!memcmp(header + 8, "\000\010", 2) ||
381 !memcmp(header + 8, "\000\030", 2))
382 status = _cupsImageReadPIX(img, fp, primary, secondary, saturation, hue,
383 lut);
384 #if defined(HAVE_LIBPNG) && defined(HAVE_LIBZ)
385 else if (!memcmp(header, "\211PNG", 4))
386 status = _cupsImageReadPNG(img, fp, primary, secondary, saturation, hue,
387 lut);
388 #endif /* HAVE_LIBPNG && HAVE_LIBZ */
389 #ifdef HAVE_LIBJPEG
390 else if (!memcmp(header, "\377\330\377", 3) && /* Start-of-Image */
391 header[3] >= 0xe0 && header[3] <= 0xef) /* APPn */
392 status = _cupsImageReadJPEG(img, fp, primary, secondary, saturation, hue,
393 lut);
394 #endif /* HAVE_LIBJPEG */
395 #ifdef HAVE_LIBTIFF
396 else if (!memcmp(header, "MM\000\052", 4) ||
397 !memcmp(header, "II\052\000", 4))
398 status = _cupsImageReadTIFF(img, fp, primary, secondary, saturation, hue,
399 lut);
400 #endif /* HAVE_LIBTIFF */
401 else
402 {
403 fclose(fp);
404 status = -1;
405 }
406
407 if (status)
408 {
409 free(img);
410 return (NULL);
411 }
412 else
413 return (img);
414 }
415
416
417 /*
418 * '_cupsImagePutCol()' - Put a column of pixels to an image.
419 */
420
421 int /* O - -1 on error, 0 on success */
_cupsImagePutCol(cups_image_t * img,int x,int y,int height,const cups_ib_t * pixels)422 _cupsImagePutCol(
423 cups_image_t *img, /* I - Image */
424 int x, /* I - Column */
425 int y, /* I - Start row */
426 int height, /* I - Column height */
427 const cups_ib_t *pixels) /* I - Pixels to put */
428 {
429 int bpp, /* Bytes per pixel */
430 twidth, /* Width of tile */
431 count; /* Number of pixels to put */
432 int tilex, /* Column within tile */
433 tiley; /* Row within tile */
434 cups_ib_t *ib; /* Pointer to pixels in tile */
435
436
437 if (img == NULL || x < 0 || x >= img->xsize || y >= img->ysize)
438 return (-1);
439
440 if (y < 0)
441 {
442 height += y;
443 y = 0;
444 }
445
446 if ((y + height) > img->ysize)
447 height = img->ysize - y;
448
449 if (height < 1)
450 return (-1);
451
452 bpp = cupsImageGetDepth(img);
453 twidth = bpp * (CUPS_TILE_SIZE - 1);
454 tilex = x / CUPS_TILE_SIZE;
455 tiley = y / CUPS_TILE_SIZE;
456
457 while (height > 0)
458 {
459 ib = get_tile(img, x, y);
460
461 if (ib == NULL)
462 return (-1);
463
464 img->tiles[tiley][tilex].dirty = 1;
465 tiley ++;
466
467 count = CUPS_TILE_SIZE - (y & (CUPS_TILE_SIZE - 1));
468 if (count > height)
469 count = height;
470
471 y += count;
472 height -= count;
473
474 for (; count > 0; count --, ib += twidth)
475 switch (bpp)
476 {
477 case 4 :
478 *ib++ = *pixels++;
479 case 3 :
480 *ib++ = *pixels++;
481 *ib++ = *pixels++;
482 case 1 :
483 *ib++ = *pixels++;
484 break;
485 }
486 }
487
488 return (0);
489 }
490
491
492 /*
493 * '_cupsImagePutRow()' - Put a row of pixels to an image.
494 */
495
496 int /* O - -1 on error, 0 on success */
_cupsImagePutRow(cups_image_t * img,int x,int y,int width,const cups_ib_t * pixels)497 _cupsImagePutRow(
498 cups_image_t *img, /* I - Image */
499 int x, /* I - Start column */
500 int y, /* I - Row */
501 int width, /* I - Row width */
502 const cups_ib_t *pixels) /* I - Pixel data */
503 {
504 int bpp, /* Bytes per pixel */
505 count; /* Number of pixels to put */
506 int tilex, /* Column within tile */
507 tiley; /* Row within tile */
508 cups_ib_t *ib; /* Pointer to pixels in tile */
509
510
511 if (img == NULL || y < 0 || y >= img->ysize || x >= img->xsize)
512 return (-1);
513
514 if (x < 0)
515 {
516 width += x;
517 x = 0;
518 }
519
520 if ((x + width) > img->xsize)
521 width = img->xsize - x;
522
523 if (width < 1)
524 return (-1);
525
526 bpp = img->colorspace < 0 ? -img->colorspace : img->colorspace;
527 tilex = x / CUPS_TILE_SIZE;
528 tiley = y / CUPS_TILE_SIZE;
529
530 while (width > 0)
531 {
532 ib = get_tile(img, x, y);
533
534 if (ib == NULL)
535 return (-1);
536
537 img->tiles[tiley][tilex].dirty = 1;
538
539 count = CUPS_TILE_SIZE - (x & (CUPS_TILE_SIZE - 1));
540 if (count > width)
541 count = width;
542 memcpy(ib, pixels, count * bpp);
543 pixels += count * bpp;
544 x += count;
545 width -= count;
546 tilex ++;
547 }
548
549 return (0);
550 }
551
552
553 /*
554 * 'cupsImageSetMaxTiles()' - Set the maximum number of tiles to cache.
555 *
556 * If the "max_tiles" argument is 0 then the maximum number of tiles is
557 * computed from the image size or the RIP_CACHE environment variable.
558 */
559
560 void
cupsImageSetMaxTiles(cups_image_t * img,int max_tiles)561 cupsImageSetMaxTiles(
562 cups_image_t *img, /* I - Image to set */
563 int max_tiles) /* I - Number of tiles to cache */
564 {
565 int cache_size, /* Size of tile cache in bytes */
566 min_tiles, /* Minimum number of tiles to cache */
567 max_size; /* Maximum cache size in bytes */
568 char *cache_env, /* Cache size environment variable */
569 cache_units[255]; /* Cache size units */
570
571
572 min_tiles = max(CUPS_TILE_MINIMUM,
573 1 + max((img->xsize + CUPS_TILE_SIZE - 1) / CUPS_TILE_SIZE,
574 (img->ysize + CUPS_TILE_SIZE - 1) / CUPS_TILE_SIZE));
575
576 if (max_tiles == 0)
577 max_tiles = ((img->xsize + CUPS_TILE_SIZE - 1) / CUPS_TILE_SIZE) *
578 ((img->ysize + CUPS_TILE_SIZE - 1) / CUPS_TILE_SIZE);
579
580 cache_size = max_tiles * CUPS_TILE_SIZE * CUPS_TILE_SIZE *
581 cupsImageGetDepth(img);
582
583 if ((cache_env = getenv("RIP_MAX_CACHE")) != NULL)
584 {
585 switch (sscanf(cache_env, "%d%254s", &max_size, cache_units))
586 {
587 case 0 :
588 max_size = 32 * 1024 * 1024;
589 break;
590 case 1 :
591 max_size *= 4 * CUPS_TILE_SIZE * CUPS_TILE_SIZE;
592 break;
593 case 2 :
594 if (tolower(cache_units[0] & 255) == 'g')
595 max_size *= 1024 * 1024 * 1024;
596 else if (tolower(cache_units[0] & 255) == 'm')
597 max_size *= 1024 * 1024;
598 else if (tolower(cache_units[0] & 255) == 'k')
599 max_size *= 1024;
600 else if (tolower(cache_units[0] & 255) == 't')
601 max_size *= 4 * CUPS_TILE_SIZE * CUPS_TILE_SIZE;
602 break;
603 }
604 }
605 else
606 max_size = 32 * 1024 * 1024;
607
608 if (cache_size > max_size)
609 max_tiles = max_size / CUPS_TILE_SIZE / CUPS_TILE_SIZE /
610 cupsImageGetDepth(img);
611
612 if (max_tiles < min_tiles)
613 max_tiles = min_tiles;
614
615 img->max_ics = max_tiles;
616
617 DEBUG_printf(("max_ics=%d...\n", img->max_ics));
618 }
619
620
621 /*
622 * 'flush_tile()' - Flush the least-recently-used tile in the cache.
623 */
624
625 static int
flush_tile(cups_image_t * img)626 flush_tile(cups_image_t *img) /* I - Image */
627 {
628 int bpp; /* Bytes per pixel */
629 cups_itile_t *tile; /* Pointer to tile */
630
631
632 bpp = cupsImageGetDepth(img);
633 if(img==NULL||img->first==NULL||img->first->tile==NULL)
634 {
635 return -1;
636 }
637 tile = img->first->tile;
638
639 if (!tile->dirty)
640 {
641 tile->ic = NULL;
642 return 0;
643 }
644
645 if (img->cachefile < 0)
646 {
647 if ((img->cachefile = cupsTempFd(img->cachename,
648 sizeof(img->cachename))) < 0)
649 {
650 tile->ic = NULL;
651 tile->dirty = 0;
652 return 0;
653 }
654
655 DEBUG_printf(("Created swap file \"%s\"...\n", img->cachename));
656 }
657
658 if (tile->pos >= 0)
659 {
660 if (lseek(img->cachefile, tile->pos, SEEK_SET) != tile->pos)
661 {
662 tile->ic = NULL;
663 tile->dirty = 0;
664 return 0;
665 }
666 }
667 else
668 {
669 if ((tile->pos = lseek(img->cachefile, 0, SEEK_END)) < 0)
670 {
671 tile->ic = NULL;
672 tile->dirty = 0;
673 return 0;
674 }
675 }
676
677 if (write(img->cachefile, tile->ic->pixels,
678 bpp * CUPS_TILE_SIZE * CUPS_TILE_SIZE) == -1)
679 DEBUG_printf(("Error writing cache tile!"));
680
681 tile->ic = NULL;
682 tile->dirty = 0;
683 return 0;
684 }
685
686
687 /*
688 * 'get_tile()' - Get a cached tile.
689 */
690
691 static cups_ib_t * /* O - Pointer to tile or NULL */
get_tile(cups_image_t * img,int x,int y)692 get_tile(cups_image_t *img, /* I - Image */
693 int x, /* I - Column in image */
694 int y) /* I - Row in image */
695 {
696 int bpp, /* Bytes per pixel */
697 tilex, /* Column within tile */
698 tiley, /* Row within tile */
699 xtiles, /* Number of tiles horizontally */
700 ytiles; /* Number of tiles vertically */
701 cups_ic_t *ic; /* Cache pointer */
702 cups_itile_t *tile; /* Tile pointer */
703
704
705 if (img->tiles == NULL)
706 {
707 xtiles = (img->xsize + CUPS_TILE_SIZE - 1) / CUPS_TILE_SIZE;
708 ytiles = (img->ysize + CUPS_TILE_SIZE - 1) / CUPS_TILE_SIZE;
709
710 DEBUG_printf(("Creating tile array (%dx%d)\n", xtiles, ytiles));
711
712 if ((img->tiles = calloc(sizeof(cups_itile_t *), ytiles)) == NULL)
713 return (NULL);
714
715 if ((tile = calloc(xtiles * sizeof(cups_itile_t), ytiles)) == NULL)
716 return (NULL);
717
718 for (tiley = 0; tiley < ytiles; tiley ++)
719 {
720 img->tiles[tiley] = tile;
721 for (tilex = xtiles; tilex > 0; tilex --, tile ++)
722 tile->pos = -1;
723 }
724 }
725
726 bpp = cupsImageGetDepth(img);
727 tilex = x / CUPS_TILE_SIZE;
728 tiley = y / CUPS_TILE_SIZE;
729 tile = img->tiles[tiley] + tilex;
730 x &= (CUPS_TILE_SIZE - 1);
731 y &= (CUPS_TILE_SIZE - 1);
732
733 if ((ic = tile->ic) == NULL)
734 {
735 if (img->num_ics < img->max_ics)
736 {
737 if ((ic = calloc(sizeof(cups_ic_t) +
738 bpp * CUPS_TILE_SIZE * CUPS_TILE_SIZE, 1)) == NULL)
739 {
740 if (img->num_ics == 0)
741 return (NULL);
742
743 flush_tile(img);
744 ic = img->first;
745 }
746 else
747 {
748 ic->pixels = ((cups_ib_t *)ic) + sizeof(cups_ic_t);
749
750 img->num_ics ++;
751
752 DEBUG_printf(("Allocated cache tile %d (%p)...\n", img->num_ics, ic));
753 }
754 }
755 else
756 {
757 DEBUG_printf(("Flushing old cache tile (%p)...\n", img->first));
758
759 int res = flush_tile(img);
760 if(res)
761 {
762 return NULL;
763 }
764 ic = img->first;
765 }
766
767 ic->tile = tile;
768 tile->ic = ic;
769
770 if (tile->pos >= 0)
771 {
772 DEBUG_printf(("Loading cache tile from file position " CUPS_LLFMT "...\n",
773 CUPS_LLCAST tile->pos));
774
775 lseek(img->cachefile, tile->pos, SEEK_SET);
776 if (read(img->cachefile, ic->pixels,
777 bpp * CUPS_TILE_SIZE * CUPS_TILE_SIZE) == -1)
778 DEBUG_printf(("Error reading cache tile!"));
779 }
780 else
781 {
782 DEBUG_puts("Clearing cache tile...");
783
784 memset(ic->pixels, 0, bpp * CUPS_TILE_SIZE * CUPS_TILE_SIZE);
785 }
786 }
787
788 if (ic == img->first)
789 {
790 if (ic->next != NULL)
791 ic->next->prev = NULL;
792
793 img->first = ic->next;
794 ic->next = NULL;
795 ic->prev = NULL;
796 }
797 else if (img->first == NULL)
798 img->first = ic;
799
800 if (ic != img->last)
801 {
802 /*
803 * Remove the cache entry from the list...
804 */
805
806 if (ic->prev != NULL)
807 ic->prev->next = ic->next;
808 if (ic->next != NULL)
809 ic->next->prev = ic->prev;
810
811 /*
812 * And add it to the end...
813 */
814
815 if (img->last != NULL)
816 img->last->next = ic;
817
818 ic->prev = img->last;
819 img->last = ic;
820 }
821
822 ic->next = NULL;
823
824 return (ic->pixels + bpp * (y * CUPS_TILE_SIZE + x));
825 }
826
827 /*
828 * Crop a image.
829 * (posw,posh): Position of left corner
830 * (width,height): width and height of required image.
831 */
cupsImageCrop(cups_image_t * img,int posw,int posh,int width,int height)832 cups_image_t* cupsImageCrop(cups_image_t* img,int posw,int posh,int width,int height)
833 {
834 int image_width = cupsImageGetWidth(img);
835 cups_image_t* temp=calloc(sizeof(cups_image_t),1);
836 cups_ib_t *pixels=(cups_ib_t*)malloc(img->xsize*cupsImageGetDepth(img));
837 temp->cachefile = -1;
838 temp->max_ics = CUPS_TILE_MINIMUM;
839 temp->colorspace=img->colorspace;
840 temp->xppi = img->xppi;
841 temp->yppi = img->yppi;
842 temp->num_ics = 0;
843 temp->first =temp->last = NULL;
844 temp->tiles = NULL;
845 temp->xsize = width;
846 temp->ysize = height;
847 for(int i=posh;i<min(cupsImageGetHeight(img),posh+height);i++){
848 cupsImageGetRow(img,posw,i,min(width,image_width-posw),pixels);
849 _cupsImagePutRow(temp,0,i-posh,min(width,image_width-posw),pixels);
850 }
851 free(pixels);
852 return temp;
853 }
854
855 #ifdef HAVE_EXIF
856 /*
857 helper function required by EXIF read function
858 */
859
trim_spaces(char * buf)860 static void trim_spaces(char *buf)
861 {
862 char *s = buf - 1;
863 for (; *buf; ++buf)
864 {
865 if (*buf != ' ')
866 s = buf;
867 }
868 *++s = 0; /* null terminate the string on the first of the final spaces */
869 }
870
871 /*
872 implementation for EXIF read function
873 */
874
875 /*
876 helper function to extract bytes from image files
877 */
878
find_bytes(FILE * fp,long int * size)879 static unsigned char *find_bytes(FILE *fp, long int *size)
880 {
881 unsigned char *buf;
882
883 long int originalOffset = ftell(fp);
884 fseek(fp, 0L, SEEK_END);
885
886 // calculating the size of the file
887 long int res = ftell(fp);
888
889 buf = (unsigned char *)malloc(res * sizeof(unsigned char) + 1);
890 fseek(fp, 0, SEEK_SET);
891
892 if (fread(buf, 1, res, fp) < res)
893 {
894 free(buf);
895 buf = NULL;
896 *size = 0;
897 }
898 else
899 *size = res + 1;
900
901 fseek(fp, originalOffset, SEEK_SET);
902
903 return buf;
904 }
905
_cupsImageReadEXIF(cups_image_t * img,FILE * fp)906 int _cupsImageReadEXIF(cups_image_t *img, FILE *fp)
907 {
908
909 if (fp == NULL)
910 {
911 return -1;
912 }
913
914 long int bufSize = 0;
915
916 unsigned char *buf = find_bytes(fp, &bufSize);
917
918 ExifData *ed = NULL;
919
920 if (buf == NULL || bufSize <= 0 ||
921 (ed = exif_data_new_from_data(buf, bufSize)) == NULL)
922 {
923 DEBUG_printf(("DEBUG: No EXIF data found"));
924 return 2;
925 }
926
927 ExifIfd ifd = EXIF_IFD_0;
928 ExifTag tagX = EXIF_TAG_X_RESOLUTION;
929 ExifTag tagY = EXIF_TAG_Y_RESOLUTION;
930
931 ExifEntry *entryX = exif_content_get_entry(ed->ifd[ifd], tagX);
932
933 ExifEntry *entryY = exif_content_get_entry(ed->ifd[ifd], tagY);
934
935 if (entryX == NULL || entryY == NULL)
936 {
937 DEBUG_printf(("DEBUG: No EXIF data found"));
938 return 2;
939 }
940
941 if (entryX)
942 {
943 char buf1[1024];
944
945 exif_entry_get_value(entryX, buf1, sizeof(buf1));
946
947 trim_spaces(buf1);
948
949 if (*buf1)
950 {
951 int xRes;
952 sscanf(buf1, "%d", &xRes);
953 img->xppi = xRes;
954 }
955 else{
956 free(buf);
957 return 2;
958 }
959 }
960
961 if (entryY)
962 {
963 char buf2[1024];
964
965 exif_entry_get_value(entryY, buf2, sizeof(buf2));
966 trim_spaces(buf2);
967
968 if (*buf2)
969 {
970 int yRes;
971 sscanf(buf2, "%d", &yRes);
972 img->yppi = yRes;
973 }
974 else{
975 free(buf);
976 return 2;
977 }
978 }
979
980 free(buf);
981 return 1;
982 }
983 #endif
984