#include "image-private.h"
static void flush_tile(cups_image_t *img);
static cups_ib_t *get_tile(cups_image_t *img, int x, int y);
void
cupsImageClose(cups_image_t *img)
{
cups_ic_t *current,
*next;
if (img->cachefile >= 0)
{
DEBUG_printf(("Closing/removing swap file \"%s\"...\n", img->cachename));
close(img->cachefile);
unlink(img->cachename);
}
DEBUG_puts("Freeing memory...");
for (current = img->first, next = NULL; current != NULL; current = next)
{
DEBUG_printf(("Freeing cache (%p, next = %p)...\n", current, next));
next = current->next;
free(current);
}
if (img->tiles != NULL)
{
DEBUG_printf(("Freeing tiles (%p)...\n", img->tiles[0]));
free(img->tiles[0]);
DEBUG_printf(("Freeing tile pointers (%p)...\n", img->tiles));
free(img->tiles);
}
free(img);
}
int
cupsImageGetCol(cups_image_t *img,
int x,
int y,
int height,
cups_ib_t *pixels)
{
int bpp,
twidth,
count;
const cups_ib_t *ib;
if (img == NULL || x < 0 || x >= img->xsize || y >= img->ysize)
return (-1);
if (y < 0)
{
height += y;
y = 0;
}
if ((y + height) > img->ysize)
height = img->ysize - y;
if (height < 1)
return (-1);
bpp = cupsImageGetDepth(img);
twidth = bpp * (CUPS_TILE_SIZE - 1);
while (height > 0)
{
ib = get_tile(img, x, y);
if (ib == NULL)
return (-1);
count = CUPS_TILE_SIZE - (y & (CUPS_TILE_SIZE - 1));
if (count > height)
count = height;
y += count;
height -= count;
for (; count > 0; count --, ib += twidth)
switch (bpp)
{
case 4 :
*pixels++ = *ib++;
case 3 :
*pixels++ = *ib++;
*pixels++ = *ib++;
case 1 :
*pixels++ = *ib++;
break;
}
}
return (0);
}
cups_icspace_t
cupsImageGetColorSpace(
cups_image_t *img)
{
return (img->colorspace);
}
int
cupsImageGetDepth(cups_image_t *img)
{
return (abs(img->colorspace));
}
unsigned
cupsImageGetHeight(cups_image_t *img)
{
return (img->ysize);
}
int
cupsImageGetRow(cups_image_t *img,
int x,
int y,
int width,
cups_ib_t *pixels)
{
int bpp,
count;
const cups_ib_t *ib;
if (img == NULL || y < 0 || y >= img->ysize || x >= img->xsize)
return (-1);
if (x < 0)
{
width += x;
x = 0;
}
if ((x + width) > img->xsize)
width = img->xsize - x;
if (width < 1)
return (-1);
bpp = img->colorspace < 0 ? -img->colorspace : img->colorspace;
while (width > 0)
{
ib = get_tile(img, x, y);
if (ib == NULL)
return (-1);
count = CUPS_TILE_SIZE - (x & (CUPS_TILE_SIZE - 1));
if (count > width)
count = width;
memcpy(pixels, ib, count * bpp);
pixels += count * bpp;
x += count;
width -= count;
}
return (0);
}
unsigned
cupsImageGetWidth(cups_image_t *img)
{
return (img->xsize);
}
unsigned
cupsImageGetXPPI(cups_image_t *img)
{
return (img->xppi);
}
unsigned
cupsImageGetYPPI(cups_image_t *img)
{
return (img->yppi);
}
cups_image_t *
cupsImageOpen(
const char *filename,
cups_icspace_t primary,
cups_icspace_t secondary,
int saturation,
int hue,
const cups_ib_t *lut)
{
FILE *fp;
unsigned char header[16],
header2[16];
cups_image_t *img;
int status;
DEBUG_printf(("cupsImageOpen(\"%s\", %d, %d, %d, %d, %p)\n",
filename ? filename : "(null)", primary, secondary,
saturation, hue, lut));
if ((fp = fopen(filename, "r")) == NULL)
return (NULL);
if (fread(header, 1, sizeof(header), fp) == 0)
{
fclose(fp);
return (NULL);
}
fseek(fp, 2048, SEEK_SET);
memset(header2, 0, sizeof(header2));
fread(header2, 1, sizeof(header2), fp);
fseek(fp, 0, SEEK_SET);
img = calloc(sizeof(cups_image_t), 1);
if (img == NULL)
{
fclose(fp);
return (NULL);
}
img->max_ics = CUPS_TILE_MINIMUM;
img->xppi = 128;
img->yppi = 128;
if (!memcmp(header, "GIF87a", 6) || !memcmp(header, "GIF89a", 6))
status = _cupsImageReadGIF(img, fp, primary, secondary, saturation, hue,
lut);
else if (!memcmp(header, "BM", 2))
status = _cupsImageReadBMP(img, fp, primary, secondary, saturation, hue,
lut);
else if (header[0] == 0x01 && header[1] == 0xda)
status = _cupsImageReadSGI(img, fp, primary, secondary, saturation, hue,
lut);
else if (header[0] == 0x59 && header[1] == 0xa6 &&
header[2] == 0x6a && header[3] == 0x95)
status = _cupsImageReadSunRaster(img, fp, primary, secondary, saturation,
hue, lut);
else if (header[0] == 'P' && header[1] >= '1' && header[1] <= '6')
status = _cupsImageReadPNM(img, fp, primary, secondary, saturation, hue,
lut);
else if (!memcmp(header2, "PCD_IPI", 7))
status = _cupsImageReadPhotoCD(img, fp, primary, secondary, saturation,
hue, lut);
else if (!memcmp(header + 8, "\000\010", 2) ||
!memcmp(header + 8, "\000\030", 2))
status = _cupsImageReadPIX(img, fp, primary, secondary, saturation, hue,
lut);
#if defined(HAVE_LIBPNG) && defined(HAVE_LIBZ)
else if (!memcmp(header, "\211PNG", 4))
status = _cupsImageReadPNG(img, fp, primary, secondary, saturation, hue,
lut);
#endif
#ifdef HAVE_LIBJPEG
else if (!memcmp(header, "\377\330\377", 3) &&
header[3] >= 0xe0 && header[3] <= 0xef)
status = _cupsImageReadJPEG(img, fp, primary, secondary, saturation, hue,
lut);
#endif
#ifdef HAVE_LIBTIFF
else if (!memcmp(header, "MM\000\052", 4) ||
!memcmp(header, "II\052\000", 4))
status = _cupsImageReadTIFF(img, fp, primary, secondary, saturation, hue,
lut);
#endif
else
{
fclose(fp);
status = -1;
}
if (status)
{
free(img);
return (NULL);
}
else
return (img);
}
int
_cupsImagePutCol(
cups_image_t *img,
int x,
int y,
int height,
const cups_ib_t *pixels)
{
int bpp,
twidth,
count;
int tilex,
tiley;
cups_ib_t *ib;
if (img == NULL || x < 0 || x >= img->xsize || y >= img->ysize)
return (-1);
if (y < 0)
{
height += y;
y = 0;
}
if ((y + height) > img->ysize)
height = img->ysize - y;
if (height < 1)
return (-1);
bpp = cupsImageGetDepth(img);
twidth = bpp * (CUPS_TILE_SIZE - 1);
tilex = x / CUPS_TILE_SIZE;
tiley = y / CUPS_TILE_SIZE;
while (height > 0)
{
ib = get_tile(img, x, y);
if (ib == NULL)
return (-1);
img->tiles[tiley][tilex].dirty = 1;
tiley ++;
count = CUPS_TILE_SIZE - (y & (CUPS_TILE_SIZE - 1));
if (count > height)
count = height;
y += count;
height -= count;
for (; count > 0; count --, ib += twidth)
switch (bpp)
{
case 4 :
*ib++ = *pixels++;
case 3 :
*ib++ = *pixels++;
*ib++ = *pixels++;
case 1 :
*ib++ = *pixels++;
break;
}
}
return (0);
}
int
_cupsImagePutRow(
cups_image_t *img,
int x,
int y,
int width,
const cups_ib_t *pixels)
{
int bpp,
count;
int tilex,
tiley;
cups_ib_t *ib;
if (img == NULL || y < 0 || y >= img->ysize || x >= img->xsize)
return (-1);
if (x < 0)
{
width += x;
x = 0;
}
if ((x + width) > img->xsize)
width = img->xsize - x;
if (width < 1)
return (-1);
bpp = img->colorspace < 0 ? -img->colorspace : img->colorspace;
tilex = x / CUPS_TILE_SIZE;
tiley = y / CUPS_TILE_SIZE;
while (width > 0)
{
ib = get_tile(img, x, y);
if (ib == NULL)
return (-1);
img->tiles[tiley][tilex].dirty = 1;
count = CUPS_TILE_SIZE - (x & (CUPS_TILE_SIZE - 1));
if (count > width)
count = width;
memcpy(ib, pixels, count * bpp);
pixels += count * bpp;
x += count;
width -= count;
tilex ++;
}
return (0);
}
void
cupsImageSetMaxTiles(
cups_image_t *img,
int max_tiles)
{
int cache_size,
min_tiles,
max_size;
char *cache_env,
cache_units[255];
min_tiles = max(CUPS_TILE_MINIMUM,
1 + max((img->xsize + CUPS_TILE_SIZE - 1) / CUPS_TILE_SIZE,
(img->ysize + CUPS_TILE_SIZE - 1) / CUPS_TILE_SIZE));
if (max_tiles == 0)
max_tiles = ((img->xsize + CUPS_TILE_SIZE - 1) / CUPS_TILE_SIZE) *
((img->ysize + CUPS_TILE_SIZE - 1) / CUPS_TILE_SIZE);
cache_size = max_tiles * CUPS_TILE_SIZE * CUPS_TILE_SIZE *
cupsImageGetDepth(img);
if ((cache_env = getenv("RIP_MAX_CACHE")) != NULL)
{
switch (sscanf(cache_env, "%d%254s", &max_size, cache_units))
{
case 0 :
max_size = 32 * 1024 * 1024;
break;
case 1 :
max_size *= 4 * CUPS_TILE_SIZE * CUPS_TILE_SIZE;
break;
case 2 :
if (tolower(cache_units[0] & 255) == 'g')
max_size *= 1024 * 1024 * 1024;
else if (tolower(cache_units[0] & 255) == 'm')
max_size *= 1024 * 1024;
else if (tolower(cache_units[0] & 255) == 'k')
max_size *= 1024;
else if (tolower(cache_units[0] & 255) == 't')
max_size *= 4 * CUPS_TILE_SIZE * CUPS_TILE_SIZE;
break;
}
}
else
max_size = 32 * 1024 * 1024;
if (cache_size > max_size)
max_tiles = max_size / CUPS_TILE_SIZE / CUPS_TILE_SIZE /
cupsImageGetDepth(img);
if (max_tiles < min_tiles)
max_tiles = min_tiles;
img->max_ics = max_tiles;
DEBUG_printf(("max_ics=%d...\n", img->max_ics));
}
static void
flush_tile(cups_image_t *img)
{
int bpp;
cups_itile_t *tile;
bpp = cupsImageGetDepth(img);
tile = img->first->tile;
if (!tile->dirty)
{
tile->ic = NULL;
return;
}
if (img->cachefile < 0)
{
if ((img->cachefile = cupsTempFd(img->cachename,
sizeof(img->cachename))) < 0)
{
tile->ic = NULL;
tile->dirty = 0;
return;
}
DEBUG_printf(("Created swap file \"%s\"...\n", img->cachename));
}
if (tile->pos >= 0)
{
if (lseek(img->cachefile, tile->pos, SEEK_SET) != tile->pos)
{
tile->ic = NULL;
tile->dirty = 0;
return;
}
}
else
{
if ((tile->pos = lseek(img->cachefile, 0, SEEK_END)) < 0)
{
tile->ic = NULL;
tile->dirty = 0;
return;
}
}
write(img->cachefile, tile->ic->pixels, bpp * CUPS_TILE_SIZE * CUPS_TILE_SIZE);
tile->ic = NULL;
tile->dirty = 0;
}
static cups_ib_t *
get_tile(cups_image_t *img,
int x,
int y)
{
int bpp,
tilex,
tiley,
xtiles,
ytiles;
cups_ic_t *ic;
cups_itile_t *tile;
if (img->tiles == NULL)
{
xtiles = (img->xsize + CUPS_TILE_SIZE - 1) / CUPS_TILE_SIZE;
ytiles = (img->ysize + CUPS_TILE_SIZE - 1) / CUPS_TILE_SIZE;
DEBUG_printf(("Creating tile array (%dx%d)\n", xtiles, ytiles));
if ((img->tiles = calloc(sizeof(cups_itile_t *), ytiles)) == NULL)
return (NULL);
if ((tile = calloc(xtiles * sizeof(cups_itile_t), ytiles)) == NULL)
return (NULL);
for (tiley = 0; tiley < ytiles; tiley ++)
{
img->tiles[tiley] = tile;
for (tilex = xtiles; tilex > 0; tilex --, tile ++)
tile->pos = -1;
}
}
bpp = cupsImageGetDepth(img);
tilex = x / CUPS_TILE_SIZE;
tiley = y / CUPS_TILE_SIZE;
tile = img->tiles[tiley] + tilex;
x &= (CUPS_TILE_SIZE - 1);
y &= (CUPS_TILE_SIZE - 1);
if ((ic = tile->ic) == NULL)
{
if (img->num_ics < img->max_ics)
{
if ((ic = calloc(sizeof(cups_ic_t) +
bpp * CUPS_TILE_SIZE * CUPS_TILE_SIZE, 1)) == NULL)
{
if (img->num_ics == 0)
return (NULL);
flush_tile(img);
ic = img->first;
}
else
{
ic->pixels = ((cups_ib_t *)ic) + sizeof(cups_ic_t);
img->num_ics ++;
DEBUG_printf(("Allocated cache tile %d (%p)...\n", img->num_ics, ic));
}
}
else
{
DEBUG_printf(("Flushing old cache tile (%p)...\n", img->first));
flush_tile(img);
ic = img->first;
}
ic->tile = tile;
tile->ic = ic;
if (tile->pos >= 0)
{
DEBUG_printf(("Loading cache tile from file position " CUPS_LLFMT "...\n",
CUPS_LLCAST tile->pos));
lseek(img->cachefile, tile->pos, SEEK_SET);
read(img->cachefile, ic->pixels, bpp * CUPS_TILE_SIZE * CUPS_TILE_SIZE);
}
else
{
DEBUG_puts("Clearing cache tile...");
memset(ic->pixels, 0, bpp * CUPS_TILE_SIZE * CUPS_TILE_SIZE);
}
}
if (ic == img->first)
{
if (ic->next != NULL)
ic->next->prev = NULL;
img->first = ic->next;
ic->next = NULL;
ic->prev = NULL;
}
else if (img->first == NULL)
img->first = ic;
if (ic != img->last)
{
if (ic->prev != NULL)
ic->prev->next = ic->next;
if (ic->next != NULL)
ic->next->prev = ic->prev;
if (img->last != NULL)
img->last->next = ic;
ic->prev = img->last;
img->last = ic;
}
ic->next = NULL;
return (ic->pixels + bpp * (y * CUPS_TILE_SIZE + x));
}