]>
git.ipfire.org Git - thirdparty/cups.git/blob - filter/image.c
9da27db69e44f63f243a88cbfa0fad189ff8d6f9
2 * "$Id: image.c 6649 2007-07-11 21:46:42Z mike $"
4 * Base image support for the Common UNIX Printing System (CUPS).
6 * Copyright 2007 by Apple Inc.
7 * Copyright 1993-2005 by Easy Software Products.
9 * These coded instructions, statements, and computer programs are the
10 * property of Apple Inc. and are protected by Federal copyright
11 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
12 * which should have been included with this file. If this file is
13 * file is missing or damaged, see the license at "http://www.cups.org/".
15 * This file is subject to the Apple OS-Developed Software exception.
19 * cupsImageClose() - Close an image file.
20 * cupsImageGetCol() - Get a column of pixels from an image.
21 * cupsImageGetColorSpace() - Get the image colorspace.
22 * cupsImageGetDepth() - Get the number of bytes per pixel.
23 * cupsImageGetHeight() - Get the height of an image.
24 * cupsImageGetRow() - Get a row of pixels from an image.
25 * cupsImageGetWidth() - Get the width of an image.
26 * cupsImageGetXPPI() - Get the horizontal resolution of an image.
27 * cupsImageGetYPPI() - Get the vertical resolution of an image.
28 * cupsImageOpen() - Open an image file and read it into memory.
29 * _cupsImagePutCol() - Put a column of pixels to an image.
30 * _cupsImagePutRow() - Put a row of pixels to an image.
31 * cupsImageSetMaxTiles() - Set the maximum number of tiles to cache.
32 * flush_tile() - Flush the least-recently-used tile in the cache.
33 * get_tile() - Get a cached tile.
37 * Include necessary headers...
40 #include "image-private.h"
47 static void flush_tile(cups_image_t
*img
);
48 static cups_ib_t
*get_tile(cups_image_t
*img
, int x
, int y
);
52 * 'cupsImageClose()' - Close an image file.
56 cupsImageClose(cups_image_t
*img
) /* I - Image to close */
58 cups_ic_t
*current
, /* Current cached tile */
59 *next
; /* Next cached tile */
63 * Wipe the tile cache file (if any)...
66 if (img
->cachefile
!= NULL
)
68 DEBUG_printf(("Closing/removing swap file \"%s\"...\n", img
->cachename
));
70 fclose(img
->cachefile
);
71 unlink(img
->cachename
);
75 * Free the image cache...
78 DEBUG_puts("Freeing memory...");
80 for (current
= img
->first
, next
= NULL
; current
!= NULL
; current
= next
)
82 DEBUG_printf(("Freeing cache (%p, next = %p)...\n", current
, next
));
89 * Free the rest of memory...
92 if (img
->tiles
!= NULL
)
94 DEBUG_printf(("Freeing tiles (%p)...\n", img
->tiles
[0]));
98 DEBUG_printf(("Freeing tile pointers (%p)...\n", img
->tiles
));
108 * 'cupsImageGetCol()' - Get a column of pixels from an image.
111 int /* O - -1 on error, 0 on success */
112 cupsImageGetCol(cups_image_t
*img
, /* I - Image */
113 int x
, /* I - Column */
114 int y
, /* I - Start row */
115 int height
, /* I - Column height */
116 cups_ib_t
*pixels
) /* O - Pixel data */
118 int bpp
, /* Bytes per pixel */
119 twidth
, /* Tile width */
120 count
; /* Number of pixels to get */
121 const cups_ib_t
*ib
; /* Pointer into tile */
124 if (img
== NULL
|| x
< 0 || x
>= img
->xsize
|| y
>= img
->ysize
)
133 if ((y
+ height
) > img
->ysize
)
134 height
= img
->ysize
- y
;
139 bpp
= cupsImageGetDepth(img
);
140 twidth
= bpp
* (CUPS_TILE_SIZE
- 1);
144 ib
= get_tile(img
, x
, y
);
149 count
= CUPS_TILE_SIZE
- (y
& (CUPS_TILE_SIZE
- 1));
156 for (; count
> 0; count
--, ib
+= twidth
)
175 * 'cupsImageGetColorSpace()' - Get the image colorspace.
178 cups_icspace_t
/* O - Colorspace */
179 cupsImageGetColorSpace(
180 cups_image_t
*img
) /* I - Image */
182 return (img
->colorspace
);
187 * 'cupsImageGetDepth()' - Get the number of bytes per pixel.
190 int /* O - Bytes per pixel */
191 cupsImageGetDepth(cups_image_t
*img
) /* I - Image */
193 return (abs(img
->colorspace
));
198 * 'cupsImageGetHeight()' - Get the height of an image.
201 unsigned /* O - Height in pixels */
202 cupsImageGetHeight(cups_image_t
*img
) /* I - Image */
209 * 'cupsImageGetRow()' - Get a row of pixels from an image.
212 int /* O - -1 on error, 0 on success */
213 cupsImageGetRow(cups_image_t
*img
, /* I - Image */
214 int x
, /* I - Start column */
216 int width
, /* I - Width of row */
217 cups_ib_t
*pixels
) /* O - Pixel data */
219 int bpp
, /* Bytes per pixel */
220 count
; /* Number of pixels to get */
221 const cups_ib_t
*ib
; /* Pointer to pixels */
224 if (img
== NULL
|| y
< 0 || y
>= img
->ysize
|| x
>= img
->xsize
)
233 if ((x
+ width
) > img
->xsize
)
234 width
= img
->xsize
- x
;
239 bpp
= img
->colorspace
< 0 ? -img
->colorspace
: img
->colorspace
;
243 ib
= get_tile(img
, x
, y
);
248 count
= CUPS_TILE_SIZE
- (x
& (CUPS_TILE_SIZE
- 1));
251 memcpy(pixels
, ib
, count
* bpp
);
252 pixels
+= count
* bpp
;
262 * 'cupsImageGetWidth()' - Get the width of an image.
265 unsigned /* O - Width in pixels */
266 cupsImageGetWidth(cups_image_t
*img
) /* I - Image */
273 * 'cupsImageGetXPPI()' - Get the horizontal resolution of an image.
276 unsigned /* O - Horizontal PPI */
277 cupsImageGetXPPI(cups_image_t
*img
) /* I - Image */
284 * 'cupsImageGetYPPI()' - Get the vertical resolution of an image.
287 unsigned /* O - Vertical PPI */
288 cupsImageGetYPPI(cups_image_t
*img
) /* I - Image */
295 * 'cupsImageOpen()' - Open an image file and read it into memory.
298 cups_image_t
* /* O - New image */
300 const char *filename
, /* I - Filename of image */
301 cups_icspace_t primary
, /* I - Primary colorspace needed */
302 cups_icspace_t secondary
, /* I - Secondary colorspace if primary no good */
303 int saturation
, /* I - Color saturation level */
304 int hue
, /* I - Color hue adjustment */
305 const cups_ib_t
*lut
) /* I - RGB gamma/brightness LUT */
307 FILE *fp
; /* File pointer */
308 unsigned char header
[16], /* First 16 bytes of file */
309 header2
[16]; /* Bytes 2048-2064 (PhotoCD) */
310 cups_image_t
*img
; /* New image buffer */
311 int status
; /* Status of load... */
314 DEBUG_printf(("cupsImageOpen(\"%s\", %d, %d, %d, %d, %p)\n",
315 filename
? filename
: "(null)", primary
, secondary
,
316 saturation
, hue
, lut
));
319 * Figure out the file type...
322 if ((fp
= fopen(filename
, "r")) == NULL
)
324 /* perror("ERROR: Unable to open image file");
328 if (fread(header
, 1, sizeof(header
), fp
) == 0)
330 /* perror("ERROR: Unable to read image file header");
336 fseek(fp
, 2048, SEEK_SET
);
337 memset(header2
, 0, sizeof(header2
));
338 fread(header2
, 1, sizeof(header2
), fp
);
339 fseek(fp
, 0, SEEK_SET
);
345 img
= calloc(sizeof(cups_image_t
), 1);
349 /* perror("ERROR: Unable to allocate memory for image file");
355 * Load the image as appropriate...
358 img
->max_ics
= CUPS_TILE_MINIMUM
;
362 if (!memcmp(header
, "GIF87a", 6) || !memcmp(header
, "GIF89a", 6))
363 status
= _cupsImageReadGIF(img
, fp
, primary
, secondary
, saturation
, hue
,
365 else if (!memcmp(header
, "BM", 2))
366 status
= _cupsImageReadBMP(img
, fp
, primary
, secondary
, saturation
, hue
,
368 else if (header
[0] == 0x01 && header
[1] == 0xda)
369 status
= _cupsImageReadSGI(img
, fp
, primary
, secondary
, saturation
, hue
,
371 else if (header
[0] == 0x59 && header
[1] == 0xa6 &&
372 header
[2] == 0x6a && header
[3] == 0x95)
373 status
= _cupsImageReadSunRaster(img
, fp
, primary
, secondary
, saturation
,
375 else if (header
[0] == 'P' && header
[1] >= '1' && header
[1] <= '6')
376 status
= _cupsImageReadPNM(img
, fp
, primary
, secondary
, saturation
, hue
,
378 else if (!memcmp(header2
, "PCD_IPI", 7))
379 status
= _cupsImageReadPhotoCD(img
, fp
, primary
, secondary
, saturation
,
381 else if (!memcmp(header
+ 8, "\000\010", 2) ||
382 !memcmp(header
+ 8, "\000\030", 2))
383 status
= _cupsImageReadPIX(img
, fp
, primary
, secondary
, saturation
, hue
,
385 #if defined(HAVE_LIBPNG) && defined(HAVE_LIBZ)
386 else if (!memcmp(header
, "\211PNG", 4))
387 status
= _cupsImageReadPNG(img
, fp
, primary
, secondary
, saturation
, hue
,
389 #endif /* HAVE_LIBPNG && HAVE_LIBZ */
391 else if (!memcmp(header
, "\377\330\377", 3) && /* Start-of-Image */
392 header
[3] >= 0xe0 && header
[3] <= 0xef) /* APPn */
393 status
= _cupsImageReadJPEG(img
, fp
, primary
, secondary
, saturation
, hue
,
395 #endif /* HAVE_LIBJPEG */
397 else if (!memcmp(header
, "MM\000\052", 4) ||
398 !memcmp(header
, "II\052\000", 4))
399 status
= _cupsImageReadTIFF(img
, fp
, primary
, secondary
, saturation
, hue
,
401 #endif /* HAVE_LIBTIFF */
404 /* fputs("ERROR: Unknown image file format!");
420 * '_cupsImagePutCol()' - Put a column of pixels to an image.
423 int /* O - -1 on error, 0 on success */
425 cups_image_t
*img
, /* I - Image */
426 int x
, /* I - Column */
427 int y
, /* I - Start row */
428 int height
, /* I - Column height */
429 const cups_ib_t
*pixels
) /* I - Pixels to put */
431 int bpp
, /* Bytes per pixel */
432 twidth
, /* Width of tile */
433 count
; /* Number of pixels to put */
434 int tilex
, /* Column within tile */
435 tiley
; /* Row within tile */
436 cups_ib_t
*ib
; /* Pointer to pixels in tile */
439 if (img
== NULL
|| x
< 0 || x
>= img
->xsize
|| y
>= img
->ysize
)
448 if ((y
+ height
) > img
->ysize
)
449 height
= img
->ysize
- y
;
454 bpp
= cupsImageGetDepth(img
);
455 twidth
= bpp
* (CUPS_TILE_SIZE
- 1);
456 tilex
= x
/ CUPS_TILE_SIZE
;
457 tiley
= y
/ CUPS_TILE_SIZE
;
461 ib
= get_tile(img
, x
, y
);
466 img
->tiles
[tiley
][tilex
].dirty
= 1;
469 count
= CUPS_TILE_SIZE
- (y
& (CUPS_TILE_SIZE
- 1));
476 for (; count
> 0; count
--, ib
+= twidth
)
495 * '_cupsImagePutRow()' - Put a row of pixels to an image.
498 int /* O - -1 on error, 0 on success */
500 cups_image_t
*img
, /* I - Image */
501 int x
, /* I - Start column */
503 int width
, /* I - Row width */
504 const cups_ib_t
*pixels
) /* I - Pixel data */
506 int bpp
, /* Bytes per pixel */
507 count
; /* Number of pixels to put */
508 int tilex
, /* Column within tile */
509 tiley
; /* Row within tile */
510 cups_ib_t
*ib
; /* Pointer to pixels in tile */
513 if (img
== NULL
|| y
< 0 || y
>= img
->ysize
|| x
>= img
->xsize
)
522 if ((x
+ width
) > img
->xsize
)
523 width
= img
->xsize
- x
;
528 bpp
= img
->colorspace
< 0 ? -img
->colorspace
: img
->colorspace
;
529 tilex
= x
/ CUPS_TILE_SIZE
;
530 tiley
= y
/ CUPS_TILE_SIZE
;
534 ib
= get_tile(img
, x
, y
);
539 img
->tiles
[tiley
][tilex
].dirty
= 1;
541 count
= CUPS_TILE_SIZE
- (x
& (CUPS_TILE_SIZE
- 1));
544 memcpy(ib
, pixels
, count
* bpp
);
545 pixels
+= count
* bpp
;
556 * 'cupsImageSetMaxTiles()' - Set the maximum number of tiles to cache.
558 * If the "max_tiles" argument is 0 then the maximum number of tiles is
559 * computed from the image size or the RIP_CACHE environment variable.
563 cupsImageSetMaxTiles(
564 cups_image_t
*img
, /* I - Image to set */
565 int max_tiles
) /* I - Number of tiles to cache */
567 int cache_size
, /* Size of tile cache in bytes */
568 min_tiles
, /* Minimum number of tiles to cache */
569 max_size
; /* Maximum cache size in bytes */
570 char *cache_env
, /* Cache size environment variable */
571 cache_units
[255]; /* Cache size units */
574 min_tiles
= max(CUPS_TILE_MINIMUM
,
575 1 + max((img
->xsize
+ CUPS_TILE_SIZE
- 1) / CUPS_TILE_SIZE
,
576 (img
->ysize
+ CUPS_TILE_SIZE
- 1) / CUPS_TILE_SIZE
));
579 max_tiles
= ((img
->xsize
+ CUPS_TILE_SIZE
- 1) / CUPS_TILE_SIZE
) *
580 ((img
->ysize
+ CUPS_TILE_SIZE
- 1) / CUPS_TILE_SIZE
);
582 cache_size
= max_tiles
* CUPS_TILE_SIZE
* CUPS_TILE_SIZE
*
583 cupsImageGetDepth(img
);
585 if ((cache_env
= getenv("RIP_MAX_CACHE")) != NULL
)
587 switch (sscanf(cache_env
, "%d%254s", &max_size
, cache_units
))
590 max_size
= 32 * 1024 * 1024;
593 max_size
*= 4 * CUPS_TILE_SIZE
* CUPS_TILE_SIZE
;
596 if (tolower(cache_units
[0] & 255) == 'g')
597 max_size
*= 1024 * 1024 * 1024;
598 else if (tolower(cache_units
[0] & 255) == 'm')
599 max_size
*= 1024 * 1024;
600 else if (tolower(cache_units
[0] & 255) == 'k')
602 else if (tolower(cache_units
[0] & 255) == 't')
603 max_size
*= 4 * CUPS_TILE_SIZE
* CUPS_TILE_SIZE
;
608 max_size
= 32 * 1024 * 1024;
610 if (cache_size
> max_size
)
611 max_tiles
= max_size
/ CUPS_TILE_SIZE
/ CUPS_TILE_SIZE
/
612 cupsImageGetDepth(img
);
614 if (max_tiles
< min_tiles
)
615 max_tiles
= min_tiles
;
617 img
->max_ics
= max_tiles
;
619 DEBUG_printf(("max_ics=%d...\n", img
->max_ics
));
624 * 'flush_tile()' - Flush the least-recently-used tile in the cache.
628 flush_tile(cups_image_t
*img
) /* I - Image */
630 int fd
; /* Cache file descriptor */
631 int bpp
; /* Bytes per pixel */
632 cups_itile_t
*tile
; /* Pointer to tile */
635 bpp
= cupsImageGetDepth(img
);
636 tile
= img
->first
->tile
;
644 if (img
->cachefile
== NULL
)
646 if ((fd
= cupsTempFd(img
->cachename
, sizeof(img
->cachename
))) < 0)
648 /* perror("ERROR: Unable to create image swap file");
654 DEBUG_printf(("Created swap file \"%s\"...\n", img
->cachename
));
656 if ((img
->cachefile
= fdopen(fd
, "wb+")) == NULL
)
658 /* perror("ERROR: Unable to create image swap file");
660 unlink(img
->cachename
);
669 if (ftell(img
->cachefile
) != tile
->pos
)
670 if (fseek(img
->cachefile
, tile
->pos
, SEEK_SET
))
672 /* perror("ERROR: Unable to seek in swap file");
680 if (fseek(img
->cachefile
, 0, SEEK_END
))
682 /* perror("ERROR: Unable to append to swap file");
688 tile
->pos
= ftell(img
->cachefile
);
692 /* if (fwrite(tile->ic->pixels, bpp, CUPS_TILE_SIZE * CUPS_TILE_SIZE,
694 perror("ERROR: Unable to write tile to swap file");
696 DEBUG_printf(("Wrote tile at position %ld...\n", tile->pos));
699 fwrite(tile
->ic
->pixels
, bpp
, CUPS_TILE_SIZE
* CUPS_TILE_SIZE
,
708 * 'get_tile()' - Get a cached tile.
711 static cups_ib_t
* /* O - Pointer to tile or NULL */
712 get_tile(cups_image_t
*img
, /* I - Image */
713 int x
, /* I - Column in image */
714 int y
) /* I - Row in image */
716 int bpp
, /* Bytes per pixel */
717 tilex
, /* Column within tile */
718 tiley
, /* Row within tile */
719 xtiles
, /* Number of tiles horizontally */
720 ytiles
; /* Number of tiles vertically */
721 cups_ic_t
*ic
; /* Cache pointer */
722 cups_itile_t
*tile
; /* Tile pointer */
725 if (img
->tiles
== NULL
)
727 xtiles
= (img
->xsize
+ CUPS_TILE_SIZE
- 1) / CUPS_TILE_SIZE
;
728 ytiles
= (img
->ysize
+ CUPS_TILE_SIZE
- 1) / CUPS_TILE_SIZE
;
730 DEBUG_printf(("Creating tile array (%dx%d)\n", xtiles
, ytiles
));
732 img
->tiles
= calloc(sizeof(cups_itile_t
*), ytiles
);
733 tile
= calloc(sizeof(cups_itile_t
), xtiles
* ytiles
);
735 for (tiley
= 0; tiley
< ytiles
; tiley
++)
737 img
->tiles
[tiley
] = tile
;
738 for (tilex
= xtiles
; tilex
> 0; tilex
--, tile
++)
743 bpp
= cupsImageGetDepth(img
);
744 tilex
= x
/ CUPS_TILE_SIZE
;
745 tiley
= y
/ CUPS_TILE_SIZE
;
746 tile
= img
->tiles
[tiley
] + tilex
;
747 x
&= (CUPS_TILE_SIZE
- 1);
748 y
&= (CUPS_TILE_SIZE
- 1);
750 if ((ic
= tile
->ic
) == NULL
)
752 if (img
->num_ics
< img
->max_ics
)
754 ic
= calloc(sizeof(cups_ic_t
) + bpp
* CUPS_TILE_SIZE
*
756 ic
->pixels
= ((cups_ib_t
*)ic
) + sizeof(cups_ic_t
);
760 DEBUG_printf(("Allocated cache tile %d (%p)...\n", img
->num_ics
, ic
));
764 DEBUG_printf(("Flushing old cache tile (%p)...\n", img
->first
));
775 DEBUG_printf(("Loading cache tile from file position %ld...\n",
778 if (ftell(img
->cachefile
) != tile
->pos
)
779 fseek(img
->cachefile
, tile
->pos
, SEEK_SET
);
780 /* if (fseek(img->cachefile, tile->pos, SEEK_SET))
784 fread(ic
->pixels
, bpp
, CUPS_TILE_SIZE
* CUPS_TILE_SIZE
, img
->cachefile
);
788 DEBUG_puts("Clearing cache tile...");
790 memset(ic
->pixels
, 0, bpp
* CUPS_TILE_SIZE
* CUPS_TILE_SIZE
);
794 if (ic
== img
->first
)
796 if (ic
->next
!= NULL
)
797 ic
->next
->prev
= NULL
;
799 img
->first
= ic
->next
;
803 else if (img
->first
== NULL
)
809 * Remove the cache entry from the list...
812 if (ic
->prev
!= NULL
)
813 ic
->prev
->next
= ic
->next
;
814 if (ic
->next
!= NULL
)
815 ic
->next
->prev
= ic
->prev
;
818 * And add it to the end...
821 if (img
->last
!= NULL
)
822 img
->last
->next
= ic
;
824 ic
->prev
= img
->last
;
830 return (ic
->pixels
+ bpp
* (y
* CUPS_TILE_SIZE
+ x
));
835 * End of "$Id: image.c 6649 2007-07-11 21:46:42Z mike $".