#include "common.h"
#include "image.h"
#include <math.h>
int Flip = 0,
XPosition = 0,
YPosition = 0,
Collate = 0,
Copies = 1;
static void ps_hex(ib_t *, int, int);
static void ps_ascii85(ib_t *, int, int);
int
main(int argc,
char *argv[])
{
image_t *img;
float xprint,
yprint,
xinches,
yinches;
float xsize,
ysize,
xsize2,
ysize2;
float aspect;
int xpages,
ypages,
xpage,
ypage,
page;
int x0, y0,
x1, y1;
ib_t *row;
int y;
int colorspace;
int out_offset,
out_length;
ppd_file_t *ppd;
ppd_choice_t *choice;
int num_options;
cups_option_t *options;
const char *val;
int slowcollate;
float g;
float b;
float zoom;
int xppi, yppi;
int hue, sat;
int realcopies;
float left, top;
char filename[1024];
time_t curtime;
struct tm *curtm;
char curdate[255];
setbuf(stderr, NULL);
if (argc < 6 || argc > 7)
{
fputs("ERROR: imagetops job-id user title copies options [file]\n", stderr);
return (1);
}
fprintf(stderr, "INFO: %s %s %s %s %s %s %s\n", argv[0], argv[1], argv[2],
argv[3], argv[4], argv[5], argv[6] ? argv[6] : "(null)");
if (argc == 6)
{
int fd;
char buffer[8192];
int bytes;
if ((fd = cupsTempFd(filename, sizeof(filename))) < 0)
{
perror("ERROR: Unable to copy image file");
return (1);
}
fprintf(stderr, "DEBUG: imagetoraster - copying to temp print file \"%s\"\n",
filename);
while ((bytes = fread(buffer, 1, sizeof(buffer), stdin)) > 0)
write(fd, buffer, bytes);
close(fd);
}
else
strlcpy(filename, argv[6], sizeof(filename));
zoom = 0.0;
xppi = 0;
yppi = 0;
hue = 0;
sat = 100;
g = 1.0;
b = 1.0;
Copies = atoi(argv[4]);
options = NULL;
num_options = cupsParseOptions(argv[5], 0, &options);
ppd = SetCommonOptions(num_options, options, 1);
if ((val = cupsGetOption("multiple-document-handling", num_options, options)) != NULL)
{
Collate = strcasecmp(val, "separate-documents-uncollated-copies") != 0;
}
if ((val = cupsGetOption("Collate", num_options, options)) != NULL &&
strcasecmp(val, "True") == 0)
Collate = 1;
if ((val = cupsGetOption("gamma", num_options, options)) != NULL)
g = atoi(val) * 0.001f;
if ((val = cupsGetOption("brightness", num_options, options)) != NULL)
b = atoi(val) * 0.01f;
if ((val = cupsGetOption("scaling", num_options, options)) != NULL)
zoom = atoi(val) * 0.01;
if ((val = cupsGetOption("ppi", num_options, options)) != NULL)
if (sscanf(val, "%dx%d", &xppi, &yppi) < 2)
yppi = xppi;
if ((val = cupsGetOption("position", num_options, options)) != NULL)
{
if (strcasecmp(val, "center") == 0)
{
XPosition = 0;
YPosition = 0;
}
else if (strcasecmp(val, "top") == 0)
{
XPosition = 0;
YPosition = 1;
}
else if (strcasecmp(val, "left") == 0)
{
XPosition = -1;
YPosition = 0;
}
else if (strcasecmp(val, "right") == 0)
{
XPosition = 1;
YPosition = 0;
}
else if (strcasecmp(val, "top-left") == 0)
{
XPosition = -1;
YPosition = 1;
}
else if (strcasecmp(val, "top-right") == 0)
{
XPosition = 1;
YPosition = 1;
}
else if (strcasecmp(val, "bottom") == 0)
{
XPosition = 0;
YPosition = -1;
}
else if (strcasecmp(val, "bottom-left") == 0)
{
XPosition = -1;
YPosition = -1;
}
else if (strcasecmp(val, "bottom-right") == 0)
{
XPosition = 1;
YPosition = -1;
}
}
if ((val = cupsGetOption("saturation", num_options, options)) != NULL)
sat = atoi(val);
if ((val = cupsGetOption("hue", num_options, options)) != NULL)
hue = atoi(val);
colorspace = ColorDevice ? IMAGE_RGB_CMYK : IMAGE_WHITE;
img = ImageOpen(filename, colorspace, IMAGE_WHITE, sat, hue, NULL);
if (argc == 6)
unlink(filename);
if (img == NULL)
{
fputs("ERROR: Unable to open image file for printing!\n", stderr);
ppdClose(ppd);
return (1);
}
colorspace = img->colorspace;
xprint = (PageRight - PageLeft) / 72.0;
yprint = (PageTop - PageBottom) / 72.0;
if (zoom == 0.0 && xppi == 0)
{
xppi = img->xppi;
yppi = img->yppi;
}
if (yppi == 0)
yppi = xppi;
if (xppi > 0)
{
xinches = (float)img->xsize / (float)xppi;
yinches = (float)img->ysize / (float)yppi;
if ((val = cupsGetOption("natural-scaling", num_options, options)) != NULL)
{
xinches = xinches * atoi(val) / 100;
yinches = yinches * atoi(val) / 100;
}
if (cupsGetOption("orientation-requested", num_options, options) == NULL &&
cupsGetOption("landscape", num_options, options) == NULL)
{
if ((xinches > xprint || yinches > yprint) &&
xinches <= yprint && yinches <= xprint)
{
Orientation = (Orientation + 1) & 3;
xsize = yprint;
yprint = xprint;
xprint = xsize;
xsize = PageLeft;
PageLeft = PageBottom;
PageBottom = PageWidth - PageRight;
PageRight = PageTop;
PageTop = PageLength - xsize;
xsize = PageWidth;
PageWidth = PageLength;
PageLength = xsize;
}
}
}
else
{
aspect = (float)img->yppi / (float)img->xppi;
fprintf(stderr, "DEBUG: img->xppi = %d, img->yppi = %d, aspect = %f\n",
img->xppi, img->yppi, aspect);
xsize = xprint * zoom;
ysize = xsize * img->ysize / img->xsize / aspect;
if (ysize > (yprint * zoom))
{
ysize = yprint * zoom;
xsize = ysize * img->xsize * aspect / img->ysize;
}
xsize2 = yprint * zoom;
ysize2 = xsize2 * img->ysize / img->xsize / aspect;
if (ysize2 > (xprint * zoom))
{
ysize2 = xprint * zoom;
xsize2 = ysize2 * img->xsize * aspect / img->ysize;
}
fprintf(stderr, "DEBUG: xsize = %.0f, ysize = %.0f\n", xsize, ysize);
fprintf(stderr, "DEBUG: xsize2 = %.0f, ysize2 = %.0f\n", xsize2, ysize2);
if (cupsGetOption("orientation-requested", num_options, options) == NULL &&
cupsGetOption("landscape", num_options, options) == NULL)
{
if ((xsize * ysize) < (xsize2 * xsize2))
{
Orientation = 1;
xinches = xsize2;
yinches = ysize2;
xprint = (PageTop - PageBottom) / 72.0;
yprint = (PageRight - PageLeft) / 72.0;
xsize = PageLeft;
PageLeft = PageBottom;
PageBottom = PageWidth - PageRight;
PageRight = PageTop;
PageTop = PageLength - xsize;
xsize = PageWidth;
PageWidth = PageLength;
PageLength = xsize;
}
else
{
Orientation = 0;
xinches = xsize;
yinches = ysize;
}
}
else if (Orientation & 1)
{
xinches = xsize2;
yinches = ysize2;
xprint = (PageTop - PageBottom) / 72.0;
yprint = (PageRight - PageLeft) / 72.0;
xsize = PageLeft;
PageLeft = PageBottom;
PageBottom = PageWidth - PageRight;
PageRight = PageTop;
PageTop = PageLength - xsize;
xsize = PageWidth;
PageWidth = PageLength;
PageLength = xsize;
}
else
{
xinches = xsize;
yinches = ysize;
xprint = (PageRight - PageLeft) / 72.0;
yprint = (PageTop - PageBottom) / 72.0;
}
}
xpages = ceil(xinches / xprint);
ypages = ceil(yinches / yprint);
xprint = xinches / xpages;
yprint = yinches / ypages;
if ((choice = ppdFindMarkedChoice(ppd, "PageSize")) != NULL &&
strcasecmp(choice->choice, "Custom") == 0)
{
float width,
length;
char s[255];
if (Orientation & 1)
{
width = yprint * 72.0;
length = xprint * 72.0;
}
else
{
width = xprint * 72.0;
length = yprint * 72.0;
}
width += ppd->custom_margins[0] + ppd->custom_margins[2];
length += ppd->custom_margins[1] + ppd->custom_margins[3];
if (width < ppd->custom_min[0])
width = ppd->custom_min[0];
if (length < ppd->custom_min[1])
length = ppd->custom_min[1];
sprintf(s, "Custom.%.0fx%.0f", width, length);
ppdMarkOption(ppd, "PageSize", s);
PageWidth = width;
PageLength = length;
PageLeft = ppd->custom_margins[0];
PageRight = width - ppd->custom_margins[2];
PageBottom = ppd->custom_margins[1];
PageTop = length - ppd->custom_margins[3];
UpdatePageVars();
}
if (xpages == 1 && ypages == 1)
Collate = 0;
slowcollate = Collate && ppdFindOption(ppd, "Collate") == NULL;
if (Copies > 1 && !slowcollate)
{
realcopies = Copies;
Copies = 1;
}
else
realcopies = 1;
ppdEmit(ppd, stdout, PPD_ORDER_EXIT);
ppdEmitJCL(ppd, stdout, atoi(argv[1]), argv[2], argv[3]);
curtime = time(NULL);
curtm = localtime(&curtime);
puts("%!PS-Adobe-3.0");
printf("%%%%BoundingBox: %.0f %.0f %.0f %.0f\n", PageLeft, PageBottom,
PageRight, PageTop);
printf("%%%%LanguageLevel: %d\n", LanguageLevel);
printf("%%%%Pages: %d\n", xpages * ypages * Copies);
puts("%%DocumentData: Clean7Bit");
puts("%%DocumentNeededResources: font Helvetica-Bold");
puts("%%Creator: imagetops/" CUPS_SVERSION);
strftime(curdate, sizeof(curdate), CUPS_STRFTIME_FORMAT, curtm);
printf("%%%%CreationDate: %s\n", curdate);
printf("%%%%Title: %s\n", argv[3]);
printf("%%%%For: %s\n", argv[2]);
if (Orientation & 1)
puts("%%Orientation: Landscape");
puts("%%EndComments");
puts("%%BeginProlog");
if (ppd != NULL && ppd->patches != NULL)
puts(ppd->patches);
ppdEmit(ppd, stdout, PPD_ORDER_DOCUMENT);
ppdEmit(ppd, stdout, PPD_ORDER_ANY);
ppdEmit(ppd, stdout, PPD_ORDER_PROLOG);
if (g != 1.0 || b != 1.0)
printf("{ neg 1 add dup 0 lt { pop 1 } { %.3f exp neg 1 add } "
"ifelse %.3f mul } bind settransfer\n", g, b);
WriteLabelProlog(cupsGetOption("page-label", num_options, options),
PageBottom, PageTop, PageWidth);
if (realcopies > 1)
{
if (ppd == NULL || ppd->language_level == 1)
printf("/#copies %d def\n", realcopies);
else
printf("<</NumCopies %d>>setpagedevice\n", realcopies);
}
puts("%%EndProlog");
row = malloc(img->xsize * abs(colorspace) + 3);
for (page = 1; Copies > 0; Copies --)
for (xpage = 0; xpage < xpages; xpage ++)
for (ypage = 0; ypage < ypages; ypage ++, page ++)
{
if (ppd && ppd->num_filters == 0)
fprintf(stderr, "PAGE: %d %d\n", page, realcopies);
fprintf(stderr, "INFO: Printing page %d...\n", page);
printf("%%%%Page: %d %d\n", page, page);
ppdEmit(ppd, stdout, PPD_ORDER_PAGE);
puts("gsave");
if (Flip)
printf("%.0f 0 translate -1 1 scale\n", PageWidth);
switch (Orientation)
{
case 1 :
printf("%.0f 0 translate 90 rotate\n", PageLength);
break;
case 2 :
printf("%.0f %.0f translate 180 rotate\n", PageWidth, PageLength);
break;
case 3 :
printf("0 %.0f translate -90 rotate\n", PageWidth);
break;
}
x0 = img->xsize * xpage / xpages;
x1 = img->xsize * (xpage + 1) / xpages - 1;
y0 = img->ysize * ypage / ypages;
y1 = img->ysize * (ypage + 1) / ypages - 1;
switch (XPosition)
{
case -1 :
left = PageLeft;
break;
default :
left = (PageWidth - xprint * 72.0) * 0.5;
break;
case 1 :
left = PageRight - xprint * 72.0;
break;
}
switch (YPosition)
{
case -1 :
top = PageBottom + 72.0 * yprint;
break;
default :
top = (PageLength + yprint * 72.0) * 0.5;
break;
case 1 :
top = PageTop;
break;
}
printf("%.1f %.1f translate\n", left, top);
printf("%.3f %.3f scale\n\n",
xprint * 72.0 / (x1 - x0 + 1),
yprint * 72.0 / (y1 - y0 + 1));
if (LanguageLevel == 1)
{
printf("/picture %d string def\n", (x1 - x0 + 1) * abs(colorspace));
printf("%d %d 8[1 0 0 -1 0 1]", (x1 - x0 + 1), (y1 - y0 + 1));
if (colorspace == IMAGE_WHITE)
puts("{currentfile picture readhexstring pop} image");
else
printf("{currentfile picture readhexstring pop} false %d colorimage\n",
abs(colorspace));
for (y = y0; y <= y1; y ++)
{
ImageGetRow(img, x0, y, x1 - x0 + 1, row);
ps_hex(row, (x1 - x0 + 1) * abs(colorspace), y == y1);
}
}
else
{
switch (colorspace)
{
case IMAGE_WHITE :
puts("/DeviceGray setcolorspace");
break;
case IMAGE_RGB :
puts("/DeviceRGB setcolorspace");
break;
case IMAGE_CMYK :
puts("/DeviceCMYK setcolorspace");
break;
}
printf("<<"
"/ImageType 1"
"/Width %d"
"/Height %d"
"/BitsPerComponent 8",
x1 - x0 + 1, y1 - y0 + 1);
switch (colorspace)
{
case IMAGE_WHITE :
fputs("/Decode[0 1]", stdout);
break;
case IMAGE_RGB :
fputs("/Decode[0 1 0 1 0 1]", stdout);
break;
case IMAGE_CMYK :
fputs("/Decode[0 1 0 1 0 1 0 1]", stdout);
break;
}
fputs("/DataSource currentfile /ASCII85Decode filter", stdout);
if (((x1 - x0 + 1) / xprint) < 100.0)
fputs("/Interpolate true", stdout);
puts("/ImageMatrix[1 0 0 -1 0 1]>>image");
for (y = y0, out_offset = 0; y <= y1; y ++)
{
ImageGetRow(img, x0, y, x1 - x0 + 1, row + out_offset);
out_length = (x1 - x0 + 1) * abs(colorspace) + out_offset;
out_offset = out_length & 3;
ps_ascii85(row, out_length, y == y1);
if (out_offset > 0)
memcpy(row, row + out_length - out_offset, out_offset);
}
}
puts("grestore");
WriteLabels(Orientation);
puts("showpage");
}
puts("%%EOF");
if (ppd != NULL && ppd->jcl_end)
fputs(ppd->jcl_end, stdout);
else
putchar(0x04);
ImageClose(img);
ppdClose(ppd);
return (0);
}
static void
ps_hex(ib_t *data,
int length,
int last_line)
{
static int col = 0;
static char *hex = "0123456789ABCDEF";
while (length > 0)
{
putchar(hex[*data >> 4]);
putchar(hex[*data & 15]);
data ++;
length --;
col += 2;
if (col > 78)
{
putchar('\n');
col = 0;
}
}
if (last_line && col)
{
putchar('\n');
col = 0;
}
}
static void
ps_ascii85(ib_t *data,
int length,
int last_line)
{
unsigned b;
unsigned char c[5];
static int col = 0;
while (length > 3)
{
b = (((((data[0] << 8) | data[1]) << 8) | data[2]) << 8) | data[3];
if (b == 0)
{
putchar('z');
col ++;
}
else
{
c[4] = (b % 85) + '!';
b /= 85;
c[3] = (b % 85) + '!';
b /= 85;
c[2] = (b % 85) + '!';
b /= 85;
c[1] = (b % 85) + '!';
b /= 85;
c[0] = b + '!';
fwrite(c, 5, 1, stdout);
col += 5;
}
data += 4;
length -= 4;
if (col >= 75)
{
putchar('\n');
col = 0;
}
}
if (last_line)
{
if (length > 0)
{
memset(data + length, 0, 4 - length);
b = (((((data[0] << 8) | data[1]) << 8) | data[2]) << 8) | data[3];
c[4] = (b % 85) + '!';
b /= 85;
c[3] = (b % 85) + '!';
b /= 85;
c[2] = (b % 85) + '!';
b /= 85;
c[1] = (b % 85) + '!';
b /= 85;
c[0] = b + '!';
fwrite(c, length + 1, 1, stdout);
}
puts("~>");
col = 0;
}
}