mirror of https://github.com/GNOME/gimp.git
2266 lines
53 KiB
C
2266 lines
53 KiB
C
/*
|
|
* "$Id$"
|
|
*
|
|
* Print plug-in driver utility functions for the GIMP.
|
|
*
|
|
* Copyright 1997-2000 Michael Sweet (mike@easysw.com) and
|
|
* Robert Krawitz (rlk@alum.mit.edu)
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License as published by the Free
|
|
* Software Foundation; either version 2 of the License, or (at your option)
|
|
* any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
* for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
*/
|
|
|
|
/*
|
|
* This file must include only standard C header files. The core code must
|
|
* compile on generic platforms that don't support glib, gimp, gtk, etc.
|
|
*/
|
|
|
|
/* #define PRINT_DEBUG */
|
|
|
|
|
|
#include "print.h"
|
|
#include <math.h>
|
|
#include <limits.h>
|
|
|
|
#ifndef __GNUC__
|
|
# define inline
|
|
#endif /* !__GNUC__ */
|
|
|
|
typedef struct
|
|
{
|
|
unsigned steps;
|
|
unsigned short *composite;
|
|
unsigned short *red;
|
|
unsigned short *green;
|
|
unsigned short *blue;
|
|
unsigned shiftval;
|
|
unsigned bin_size;
|
|
unsigned bin_shift;
|
|
} lut_t;
|
|
|
|
/*
|
|
* RGB to grayscale luminance constants...
|
|
*/
|
|
|
|
#define LUM_RED 31
|
|
#define LUM_GREEN 61
|
|
#define LUM_BLUE 8
|
|
|
|
/* rgb/hsv conversions taken from Gimp common/autostretch_hsv.c */
|
|
|
|
static vars_t default_vars =
|
|
{
|
|
"", /* Name of file or command to print to */
|
|
"ps2", /* Name of printer "driver" */
|
|
"", /* Name of PPD file */
|
|
OUTPUT_COLOR, /* Color or grayscale output */
|
|
"", /* Output resolution */
|
|
"", /* Size of output media */
|
|
"", /* Type of output media */
|
|
"", /* Source of output media */
|
|
"", /* Ink type */
|
|
"", /* Dither algorithm */
|
|
1.0, /* Output brightness */
|
|
100.0, /* Scaling (100% means entire printable area, */
|
|
/* -XXX means scale by PPI) */
|
|
-1, /* Orientation (-1 = automatic) */
|
|
-1, /* X offset (-1 = center) */
|
|
-1, /* Y offset (-1 = center) */
|
|
1.0, /* Screen gamma */
|
|
1.0, /* Contrast */
|
|
1.0, /* Cyan */
|
|
1.0, /* Magenta */
|
|
1.0, /* Yellow */
|
|
0, /* Linear */
|
|
1.0, /* Output saturation */
|
|
1.0, /* Density */
|
|
IMAGE_CONTINUOUS, /* Image type */
|
|
0, /* Unit 0=Inch */
|
|
1.0, /* Application gamma placeholder */
|
|
0, /* Page width */
|
|
0 /* Page height */
|
|
};
|
|
|
|
static vars_t min_vars =
|
|
{
|
|
"", /* Name of file or command to print to */
|
|
"ps2", /* Name of printer "driver" */
|
|
"", /* Name of PPD file */
|
|
OUTPUT_COLOR, /* Color or grayscale output */
|
|
"", /* Output resolution */
|
|
"", /* Size of output media */
|
|
"", /* Type of output media */
|
|
"", /* Source of output media */
|
|
"", /* Ink type */
|
|
"", /* Dither algorithm */
|
|
0, /* Output brightness */
|
|
5.0, /* Scaling (100% means entire printable area, */
|
|
/* -XXX means scale by PPI) */
|
|
-1, /* Orientation (-1 = automatic) */
|
|
-1, /* X offset (-1 = center) */
|
|
-1, /* Y offset (-1 = center) */
|
|
0.1, /* Screen gamma */
|
|
0, /* Contrast */
|
|
0, /* Cyan */
|
|
0, /* Magenta */
|
|
0, /* Yellow */
|
|
0, /* Linear */
|
|
0, /* Output saturation */
|
|
.1, /* Density */
|
|
IMAGE_CONTINUOUS, /* Image type */
|
|
0, /* Unit 0=Inch */
|
|
1.0, /* Application gamma placeholder */
|
|
0, /* Page width */
|
|
0 /* Page height */
|
|
};
|
|
|
|
static vars_t max_vars =
|
|
{
|
|
"", /* Name of file or command to print to */
|
|
"ps2", /* Name of printer "driver" */
|
|
"", /* Name of PPD file */
|
|
OUTPUT_COLOR, /* Color or grayscale output */
|
|
"", /* Output resolution */
|
|
"", /* Size of output media */
|
|
"", /* Type of output media */
|
|
"", /* Source of output media */
|
|
"", /* Ink type */
|
|
"", /* Dither algorithm */
|
|
2.0, /* Output brightness */
|
|
100.0, /* Scaling (100% means entire printable area, */
|
|
/* -XXX means scale by PPI) */
|
|
-1, /* Orientation (-1 = automatic) */
|
|
-1, /* X offset (-1 = center) */
|
|
-1, /* Y offset (-1 = center) */
|
|
4.0, /* Screen gamma */
|
|
4.0, /* Contrast */
|
|
4.0, /* Cyan */
|
|
4.0, /* Magenta */
|
|
4.0, /* Yellow */
|
|
0, /* Linear */
|
|
9.0, /* Output saturation */
|
|
2.0, /* Density */
|
|
IMAGE_CONTINUOUS, /* Image type */
|
|
0, /* Unit 0=Inch */
|
|
1.0, /* Application gamma placeholder */
|
|
0, /* Page width */
|
|
0 /* Page height */
|
|
};
|
|
|
|
#define FMAX(a, b) ((a) > (b) ? (a) : (b))
|
|
#define FMIN(a, b) ((a) < (b) ? (a) : (b))
|
|
|
|
static inline void
|
|
calc_rgb_to_hsl(unsigned short *rgb, double *hue, double *sat,
|
|
double *lightness)
|
|
{
|
|
double red, green, blue;
|
|
double h, s, l;
|
|
double min, max;
|
|
double delta;
|
|
int maxval;
|
|
|
|
red = rgb[0] / 65535.0;
|
|
green = rgb[1] / 65535.0;
|
|
blue = rgb[2] / 65535.0;
|
|
|
|
if (red > green)
|
|
{
|
|
if (red > blue)
|
|
{
|
|
max = red;
|
|
maxval = 0;
|
|
}
|
|
else
|
|
{
|
|
max = blue;
|
|
maxval = 2;
|
|
}
|
|
min = FMIN(green, blue);
|
|
}
|
|
else
|
|
{
|
|
if (green > blue)
|
|
{
|
|
max = green;
|
|
maxval = 1;
|
|
}
|
|
else
|
|
{
|
|
max = blue;
|
|
maxval = 2;
|
|
}
|
|
min = FMIN(red, blue);
|
|
}
|
|
|
|
l = (max + min) / 2.0;
|
|
delta = max - min;
|
|
|
|
if (delta < .000001) /* Suggested by Eugene Anikin <eugene@anikin.com> */
|
|
{
|
|
s = 0.0;
|
|
h = 0.0;
|
|
}
|
|
else
|
|
{
|
|
if (l <= .5)
|
|
s = delta / (max + min);
|
|
else
|
|
s = delta / (2 - max - min);
|
|
|
|
if (maxval == 0)
|
|
h = (green - blue) / delta;
|
|
else if (maxval == 1)
|
|
h = 2 + (blue - red) / delta;
|
|
else
|
|
h = 4 + (red - green) / delta;
|
|
|
|
if (h < 0.0)
|
|
h += 6.0;
|
|
else if (h > 6.0)
|
|
h -= 6.0;
|
|
}
|
|
|
|
*hue = h;
|
|
*sat = s;
|
|
*lightness = l;
|
|
}
|
|
|
|
static inline double
|
|
hsl_value(double n1, double n2, double hue)
|
|
{
|
|
if (hue < 0)
|
|
hue += 6.0;
|
|
else if (hue > 6)
|
|
hue -= 6.0;
|
|
if (hue < 1.0)
|
|
return (n1 + (n2 - n1) * hue);
|
|
else if (hue < 3.0)
|
|
return (n2);
|
|
else if (hue < 4.0)
|
|
return (n1 + (n2 - n1) * (4.0 - hue));
|
|
else
|
|
return (n1);
|
|
}
|
|
|
|
static inline void
|
|
calc_hsl_to_rgb(unsigned short *rgb, double h, double s, double l)
|
|
{
|
|
if (s < .0000001)
|
|
{
|
|
if (l > 1)
|
|
l = 1;
|
|
else if (l < 0)
|
|
l = 0;
|
|
rgb[0] = l * 65535;
|
|
rgb[1] = l * 65535;
|
|
rgb[2] = l * 65535;
|
|
}
|
|
else
|
|
{
|
|
double m1, m2;
|
|
double h1, h2;
|
|
h1 = h + 2;
|
|
h2 = h - 2;
|
|
|
|
if (l < .5)
|
|
m2 = l * (1 + s);
|
|
else
|
|
m2 = l + s - (l * s);
|
|
m1 = (l * 2) - m2;
|
|
rgb[0] = 65535 * hsl_value(m1, m2, h1);
|
|
rgb[1] = 65535 * hsl_value(m1, m2, h);
|
|
rgb[2] = 65535 * hsl_value(m1, m2, h2);
|
|
}
|
|
}
|
|
|
|
static inline void
|
|
update_cmyk(unsigned short *rgb)
|
|
{
|
|
int c = 65535 - rgb[0];
|
|
int m = 65535 - rgb[1];
|
|
int y = 65535 - rgb[2];
|
|
int nc, nm, ny;
|
|
int k;
|
|
if (c == 0 && m == 0 && y == 0)
|
|
return;
|
|
k = FMIN(FMIN(c, m), y);
|
|
|
|
/*
|
|
* This is an attempt to achieve better color balance. The goal
|
|
* is to weaken the pure cyan, magenta, and yellow and strengthen
|
|
* pure red, green, and blue.
|
|
*
|
|
* We also don't want S=1 V=1 cyan to be 100% cyan; it's simply
|
|
* too dark.
|
|
*/
|
|
|
|
nc = (c * 3 + FMIN(c, FMAX(m, y)) * 5 + FMAX(m, y) * 0 + k) / 8;
|
|
nm = (m * 3 + FMIN(m, FMAX(c, y)) * 5 + FMAX(c, y) * 0 + k) / 8;
|
|
ny = (y * 3 + FMIN(y, FMAX(c, m)) * 5 + FMAX(c, m) * 0 + k) / 8;
|
|
|
|
/*
|
|
* Make sure we didn't go overboard. We don't want to go too
|
|
* close to white unnecessarily.
|
|
*/
|
|
nc = c + (nc - c) / 3;
|
|
nm = m + (nm - m) / 3;
|
|
ny = y + (ny - y) / 3;
|
|
|
|
if (nc > 65535)
|
|
nc = 65535;
|
|
if (nm > 65535)
|
|
nm = 65535;
|
|
if (ny > 65535)
|
|
ny = 65535;
|
|
|
|
rgb[0] = 65535 - nc;
|
|
rgb[1] = 65535 - nm;
|
|
rgb[2] = 65535 - ny;
|
|
}
|
|
|
|
/*
|
|
* A lot of this stuff needs to be factored out of here
|
|
*/
|
|
static inline unsigned short
|
|
lookup_value(unsigned short value, int lut_size, unsigned short *lut,
|
|
unsigned shiftval, unsigned bin_size, unsigned bin_shift)
|
|
{
|
|
unsigned subrange;
|
|
unsigned remainder;
|
|
unsigned below;
|
|
unsigned above;
|
|
if (lut_size == 65536)
|
|
return lut[value];
|
|
subrange = value >> bin_shift;
|
|
remainder = value & (bin_size - 1);
|
|
below = lut[subrange];
|
|
if (remainder == 0)
|
|
return below;
|
|
if (subrange == (bin_size - 1))
|
|
above = lut[subrange];
|
|
else
|
|
above = lut[subrange + 1];
|
|
if (above == below)
|
|
return above;
|
|
else
|
|
return below + (((above - below) * remainder) >> bin_shift);
|
|
}
|
|
|
|
/*
|
|
* 'gray_to_gray()' - Convert grayscale image data to grayscale (brightness
|
|
* adjusted).
|
|
*/
|
|
|
|
static void
|
|
gray_to_gray(unsigned char *grayin, /* I - RGB pixels */
|
|
unsigned short *grayout, /* O - RGB pixels */
|
|
int width, /* I - Width of row */
|
|
int bpp, /* I - Bytes-per-pixel in grayin */
|
|
unsigned char *cmap, /* I - Colormap (unused) */
|
|
const vars_t *vars
|
|
)
|
|
{
|
|
int i0 = -1;
|
|
int i1 = -1;
|
|
int use_previous = 0;
|
|
int o0 = 0;
|
|
lut_t *lut = (lut_t *)(vars->lut);
|
|
while (width > 0)
|
|
{
|
|
if (bpp == 1)
|
|
{
|
|
/*
|
|
* No alpha in image...
|
|
*/
|
|
if (i0 == grayin[0])
|
|
use_previous = 1;
|
|
else
|
|
{
|
|
use_previous = 0;
|
|
i0 = grayin[0];
|
|
grayout[0] = lut->composite[grayin[0]];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (i0 == grayin[0] && i1 == grayin[1])
|
|
use_previous = 1;
|
|
else
|
|
{
|
|
use_previous = 0;
|
|
i0 = grayin[0];
|
|
i1 = grayin[1];
|
|
grayout[0] = lut->composite[grayin[0] * grayin[1] / 255 +
|
|
255 - grayin[1]];
|
|
}
|
|
}
|
|
if (use_previous)
|
|
{
|
|
grayout[0] = o0;
|
|
}
|
|
else
|
|
{
|
|
if (vars->density != 1.0)
|
|
{
|
|
double t = (65535.0 + ((grayout[0] - 65535.0) * vars->density));
|
|
if (t < 0.0)
|
|
t = 0.0;
|
|
grayout[0] = t + .5;
|
|
}
|
|
o0 = grayout[0];
|
|
}
|
|
grayin += bpp;
|
|
grayout ++;
|
|
width --;
|
|
}
|
|
}
|
|
|
|
static void
|
|
gray_to_monochrome(unsigned char *grayin, /* I - RGB pixels */
|
|
unsigned short *grayout, /* O - RGB pixels */
|
|
int width, /* I - Width of row */
|
|
int bpp, /* I - Bytes-per-pixel in grayin */
|
|
unsigned char *cmap, /* I - Colormap (unused) */
|
|
const vars_t *vars
|
|
)
|
|
{
|
|
int i0 = -1;
|
|
int i1 = -1;
|
|
int use_previous = 0;
|
|
int o0 = 0;
|
|
lut_t *lut = (lut_t *)(vars->lut);
|
|
while (width > 0)
|
|
{
|
|
if (bpp == 1)
|
|
{
|
|
/*
|
|
* No alpha in image...
|
|
*/
|
|
if (i0 == grayin[0])
|
|
use_previous = 1;
|
|
else
|
|
{
|
|
use_previous = 0;
|
|
i0 = grayin[0];
|
|
grayout[0] = lut->composite[grayin[0]];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (i0 == grayin[0] && i1 == grayin[1])
|
|
use_previous = 1;
|
|
else
|
|
{
|
|
use_previous = 0;
|
|
i0 = grayin[0];
|
|
i1 = grayin[1];
|
|
grayout[0] = lut->composite[grayin[0] * grayin[1] / 255 +
|
|
255 - grayin[1]];
|
|
}
|
|
}
|
|
if (use_previous)
|
|
{
|
|
grayout[0] = o0;
|
|
}
|
|
else
|
|
{
|
|
if (grayout[0] < 32768)
|
|
grayout[0] = 0;
|
|
else
|
|
grayout[0] = 65535;
|
|
o0 = grayout[0];
|
|
}
|
|
grayin += bpp;
|
|
grayout ++;
|
|
width --;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* 'indexed_to_gray()' - Convert indexed image data to grayscale.
|
|
*/
|
|
|
|
static void
|
|
indexed_to_gray(unsigned char *indexed, /* I - Indexed pixels */
|
|
unsigned short *gray, /* O - Grayscale pixels */
|
|
int width, /* I - Width of row */
|
|
int bpp, /* I - bpp in indexed */
|
|
unsigned char *cmap, /* I - Colormap */
|
|
const vars_t *vars
|
|
)
|
|
{
|
|
int i0 = -1;
|
|
int i1 = -1;
|
|
int o0 = 0;
|
|
int use_previous = 0;
|
|
int i;
|
|
lut_t *lut = (lut_t *)(vars->lut);
|
|
unsigned char gray_cmap[256]; /* Grayscale colormap */
|
|
|
|
/* Really should precompute this silly thing... */
|
|
for (i = 0; i < 256; i ++, cmap += 3)
|
|
gray_cmap[i] = (cmap[0] * LUM_RED +
|
|
cmap[1] * LUM_GREEN +
|
|
cmap[2] * LUM_BLUE) / 100;
|
|
|
|
while (width > 0)
|
|
{
|
|
if (bpp == 1)
|
|
{
|
|
/*
|
|
* No alpha in image...
|
|
*/
|
|
if (i0 == indexed[0])
|
|
use_previous = 1;
|
|
else
|
|
{
|
|
use_previous = 0;
|
|
i0 = indexed[0];
|
|
gray[0] = lut->composite[gray_cmap[i0]];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (i0 == indexed[0] && i1 == indexed[1])
|
|
use_previous = 1;
|
|
else
|
|
{
|
|
use_previous = 0;
|
|
i0 = indexed[0];
|
|
i1 = indexed[1];
|
|
gray[0] = lut->composite[gray_cmap[i0 * i1 / 255]
|
|
+ 255 - i1];
|
|
}
|
|
}
|
|
if (use_previous)
|
|
{
|
|
gray[0] = o0;
|
|
}
|
|
else
|
|
{
|
|
if (vars->density != 1.0)
|
|
{
|
|
double t = (65535.0 + ((gray[0] - 65535.0) * vars->density));
|
|
if (t < 0.0)
|
|
t = 0.0;
|
|
gray[0] = t + .5;
|
|
}
|
|
o0 = gray[0];
|
|
}
|
|
indexed += bpp;
|
|
gray ++;
|
|
width --;
|
|
}
|
|
}
|
|
|
|
static void
|
|
indexed_to_monochrome(unsigned char *indexed, /* I - Indexed pixels */
|
|
unsigned short *gray, /* O - Grayscale pixels */
|
|
int width, /* I - Width of row */
|
|
int bpp, /* I - bpp in indexed */
|
|
unsigned char *cmap, /* I - Colormap */
|
|
const vars_t *vars
|
|
)
|
|
{
|
|
int i0 = -1;
|
|
int i1 = -1;
|
|
int o0 = 0;
|
|
int use_previous = 0;
|
|
int i;
|
|
lut_t *lut = (lut_t *)(vars->lut);
|
|
unsigned char gray_cmap[256]; /* Grayscale colormap */
|
|
|
|
/* Really should precompute this silly thing... */
|
|
for (i = 0; i < 256; i ++, cmap += 3)
|
|
gray_cmap[i] = (cmap[0] * LUM_RED +
|
|
cmap[1] * LUM_GREEN +
|
|
cmap[2] * LUM_BLUE) / 100;
|
|
|
|
while (width > 0)
|
|
{
|
|
if (bpp == 1)
|
|
{
|
|
/*
|
|
* No alpha in image...
|
|
*/
|
|
if (i0 == indexed[0])
|
|
use_previous = 1;
|
|
else
|
|
{
|
|
use_previous = 0;
|
|
i0 = indexed[0];
|
|
gray[0] = lut->composite[gray_cmap[i0]];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (i0 == indexed[0] && i1 == indexed[1])
|
|
use_previous = 1;
|
|
else
|
|
{
|
|
use_previous = 0;
|
|
i0 = indexed[0];
|
|
i1 = indexed[1];
|
|
gray[0] = lut->composite[gray_cmap[i0 * i1 / 255]
|
|
+ 255 - i1];
|
|
}
|
|
}
|
|
if (use_previous)
|
|
{
|
|
gray[0] = o0;
|
|
}
|
|
else
|
|
{
|
|
if (gray[0] < 32768)
|
|
gray[0] = 0;
|
|
else
|
|
gray[0] = 65535;
|
|
o0 = gray[0];
|
|
}
|
|
indexed += bpp;
|
|
gray ++;
|
|
width --;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* 'rgb_to_gray()' - Convert RGB image data to grayscale.
|
|
*/
|
|
|
|
static void
|
|
rgb_to_gray(unsigned char *rgb, /* I - RGB pixels */
|
|
unsigned short *gray, /* O - Grayscale pixels */
|
|
int width, /* I - Width of row */
|
|
int bpp, /* I - Bytes-per-pixel in RGB */
|
|
unsigned char *cmap, /* I - Colormap (unused) */
|
|
const vars_t *vars
|
|
)
|
|
{
|
|
int i0 = -1;
|
|
int i1 = -1;
|
|
int i2 = -1;
|
|
int i3 = -1;
|
|
int o0 = 0;
|
|
int use_previous = 0;
|
|
lut_t *lut = (lut_t *)(vars->lut);
|
|
while (width > 0)
|
|
{
|
|
if (bpp == 3)
|
|
{
|
|
/*
|
|
* No alpha in image...
|
|
*/
|
|
if (i0 == rgb[0] && i1 == rgb[1] && i2 == rgb[2])
|
|
use_previous = 1;
|
|
else
|
|
{
|
|
use_previous = 0;
|
|
i0 = rgb[0];
|
|
i1 = rgb[1];
|
|
i2 = rgb[2];
|
|
gray[0] = lut->composite[(rgb[0] * LUM_RED +
|
|
rgb[1] * LUM_GREEN +
|
|
rgb[2] * LUM_BLUE) / 100];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (i0 == rgb[0] && i1 == rgb[1] && i2 == rgb[2] && i3 == rgb[3])
|
|
use_previous = 1;
|
|
else
|
|
{
|
|
use_previous = 0;
|
|
i0 = rgb[0];
|
|
i1 = rgb[1];
|
|
i2 = rgb[2];
|
|
i3 = rgb[3];
|
|
|
|
gray[0] = lut->composite[((rgb[0] * LUM_RED +
|
|
rgb[1] * LUM_GREEN +
|
|
rgb[2] * LUM_BLUE) *
|
|
rgb[3] / 25500 + 255 - rgb[3])];
|
|
}
|
|
}
|
|
if (use_previous)
|
|
{
|
|
gray[0] = o0;
|
|
}
|
|
else
|
|
{
|
|
if (vars->density != 1.0)
|
|
{
|
|
double t = (65535.0 + ((gray[0] - 65535.0) * vars->density));
|
|
if (t < 0.0)
|
|
t = 0.0;
|
|
gray[0] = t + .5;
|
|
}
|
|
o0 = gray[0];
|
|
}
|
|
rgb += bpp;
|
|
gray ++;
|
|
width --;
|
|
}
|
|
}
|
|
|
|
static void
|
|
rgb_to_monochrome(unsigned char *rgb, /* I - RGB pixels */
|
|
unsigned short *gray, /* O - Grayscale pixels */
|
|
int width, /* I - Width of row */
|
|
int bpp, /* I - Bytes-per-pixel in RGB */
|
|
unsigned char *cmap, /* I - Colormap (unused) */
|
|
const vars_t *vars
|
|
)
|
|
{
|
|
int i0 = -1;
|
|
int i1 = -1;
|
|
int i2 = -1;
|
|
int i3 = -1;
|
|
int o0 = 0;
|
|
int use_previous = 0;
|
|
lut_t *lut = (lut_t *)(vars->lut);
|
|
while (width > 0)
|
|
{
|
|
if (bpp == 3)
|
|
{
|
|
/*
|
|
* No alpha in image...
|
|
*/
|
|
if (i0 == rgb[0] && i1 == rgb[1] && i2 == rgb[2])
|
|
use_previous = 1;
|
|
else
|
|
{
|
|
use_previous = 0;
|
|
i0 = rgb[0];
|
|
i1 = rgb[1];
|
|
i2 = rgb[2];
|
|
gray[0] = lut->composite[(rgb[0] * LUM_RED +
|
|
rgb[1] * LUM_GREEN +
|
|
rgb[2] * LUM_BLUE) / 100];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (i0 == rgb[0] && i1 == rgb[1] && i2 == rgb[2] && i3 == rgb[3])
|
|
use_previous = 1;
|
|
else
|
|
{
|
|
use_previous = 0;
|
|
i0 = rgb[0];
|
|
i1 = rgb[1];
|
|
i2 = rgb[2];
|
|
i3 = rgb[3];
|
|
|
|
gray[0] = lut->composite[((rgb[0] * LUM_RED +
|
|
rgb[1] * LUM_GREEN +
|
|
rgb[2] * LUM_BLUE) *
|
|
rgb[3] / 25500 + 255 - rgb[3])];
|
|
}
|
|
}
|
|
if (use_previous)
|
|
{
|
|
gray[0] = o0;
|
|
}
|
|
else
|
|
{
|
|
if (gray[0] < 32768)
|
|
gray[0] = 0;
|
|
else
|
|
gray[0] = 65535;
|
|
o0 = gray[0];
|
|
}
|
|
rgb += bpp;
|
|
gray ++;
|
|
width --;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* 'rgb_to_rgb()' - Convert rgb image data to RGB.
|
|
*/
|
|
|
|
static void
|
|
rgb_to_rgb(unsigned char *rgbin, /* I - RGB pixels */
|
|
unsigned short *rgbout, /* O - RGB pixels */
|
|
int width, /* I - Width of row */
|
|
int bpp, /* I - Bytes/pix in indexed */
|
|
unsigned char *cmap, /* I - Colormap */
|
|
const vars_t *vars
|
|
)
|
|
{
|
|
unsigned ld = vars->density * 65536;
|
|
double isat = 1.0;
|
|
double ssat = vars->saturation;
|
|
int i0 = -1;
|
|
int i1 = -1;
|
|
int i2 = -1;
|
|
int i3 = -1;
|
|
int o0 = 0;
|
|
int o1 = 0;
|
|
int o2 = 0;
|
|
int use_previous = 0;
|
|
lut_t *lut = (lut_t *)(vars->lut);
|
|
int compute_saturation = ssat <= .99999 || ssat >= 1.00001;
|
|
int split_saturation = ssat > 1.4;
|
|
if (split_saturation)
|
|
ssat = sqrt(ssat);
|
|
if (ssat > 1)
|
|
isat = 1.0 / ssat;
|
|
#if 0
|
|
printf("rgb-to-rgb: ssat=%f, isat=%f, do-sat=%d, split-sat=%d\n", ssat, isat, compute_saturation, split_saturation);
|
|
#endif
|
|
while (width > 0)
|
|
{
|
|
double h, s, v;
|
|
switch (bpp)
|
|
{
|
|
case 1:
|
|
/*
|
|
* No alpha in image, using colormap...
|
|
*/
|
|
if (i0 == rgbin[0])
|
|
use_previous = 1;
|
|
else
|
|
{
|
|
use_previous = 0;
|
|
i0 = rgbin[0];
|
|
rgbout[0] = cmap[rgbin[0] * 3 + 0] * 257;
|
|
rgbout[1] = cmap[rgbin[0] * 3 + 1] * 257;
|
|
rgbout[2] = cmap[rgbin[0] * 3 + 2] * 257;
|
|
}
|
|
break;
|
|
case 2:
|
|
if (i0 == rgbin[0] && i1 == rgbin[1])
|
|
use_previous = 1;
|
|
else
|
|
{
|
|
use_previous = 0;
|
|
i0 = rgbin[0];
|
|
i1 = rgbin[1];
|
|
rgbout[0] = (cmap[rgbin[0] * 3 + 0] *
|
|
rgbin[1] / 255 + 255 - rgbin[1]) * 257;
|
|
rgbout[1] = (cmap[rgbin[0] * 3 + 0] *
|
|
rgbin[1] / 255 + 255 - rgbin[1]) * 257;
|
|
rgbout[2] = (cmap[rgbin[0] * 3 + 0] *
|
|
rgbin[1] / 255 + 255 - rgbin[1]) * 257;
|
|
}
|
|
break;
|
|
case 3:
|
|
/*
|
|
* No alpha in image...
|
|
*/
|
|
if (i0 == rgbin[0] && i1 == rgbin[1] && i2 == rgbin[2])
|
|
use_previous = 1;
|
|
else
|
|
{
|
|
use_previous = 0;
|
|
i0 = rgbin[0];
|
|
i1 = rgbin[1];
|
|
i2 = rgbin[2];
|
|
rgbout[0] = rgbin[0] * 257;
|
|
rgbout[1] = rgbin[1] * 257;
|
|
rgbout[2] = rgbin[2] * 257;
|
|
}
|
|
break;
|
|
case 4:
|
|
if (i0 == rgbin[0] && i1 == rgbin[1] && i2 == rgbin[2] &&
|
|
i3 == rgbin[3])
|
|
use_previous = 1;
|
|
else
|
|
{
|
|
use_previous = 0;
|
|
i0 = rgbin[0];
|
|
i1 = rgbin[1];
|
|
i2 = rgbin[2];
|
|
i3 = rgbin[3];
|
|
rgbout[0] = (rgbin[0] * rgbin[3] / 255 + 255 - rgbin[3]) * 257;
|
|
rgbout[1] = (rgbin[1] * rgbin[3] / 255 + 255 - rgbin[3]) * 257;
|
|
rgbout[2] = (rgbin[2] * rgbin[3] / 255 + 255 - rgbin[3]) * 257;
|
|
}
|
|
break;
|
|
}
|
|
if (use_previous)
|
|
{
|
|
rgbout[0] = o0;
|
|
rgbout[1] = o1;
|
|
rgbout[2] = o2;
|
|
}
|
|
else
|
|
{
|
|
if (compute_saturation &&
|
|
(rgbout[0] != rgbout[1] || rgbout[0] != rgbout[2]))
|
|
{
|
|
rgbout[0] = 65535 - rgbout[0];
|
|
rgbout[1] = 65535 - rgbout[1];
|
|
rgbout[2] = 65535 - rgbout[2];
|
|
calc_rgb_to_hsl(rgbout, &h, &s, &v);
|
|
if (ssat < 1)
|
|
s *= ssat;
|
|
else
|
|
{
|
|
double s1 = s * ssat;
|
|
double s2 = 1.0 - ((1.0 - s) * isat);
|
|
s = FMIN(s1, s2);
|
|
}
|
|
if (s > 1)
|
|
s = 1.0;
|
|
calc_hsl_to_rgb(rgbout, h, s, v);
|
|
rgbout[0] = 65535 - rgbout[0];
|
|
rgbout[1] = 65535 - rgbout[1];
|
|
rgbout[2] = 65535 - rgbout[2];
|
|
}
|
|
update_cmyk(rgbout); /* Fiddle with the INPUT */
|
|
rgbout[0] = lookup_value(rgbout[0], lut->steps,
|
|
lut->red, lut->shiftval,
|
|
lut->bin_size, lut->bin_shift);
|
|
rgbout[1] = lookup_value(rgbout[1], lut->steps,
|
|
lut->green, lut->shiftval,
|
|
lut->bin_size, lut->bin_shift);
|
|
rgbout[2] = lookup_value(rgbout[2], lut->steps,
|
|
lut->blue, lut->shiftval,
|
|
lut->bin_size, lut->bin_shift);
|
|
if (split_saturation &&
|
|
(rgbout[0] != rgbout[1] || rgbout[0] != rgbout[2]))
|
|
{
|
|
rgbout[0] = 65535 - rgbout[0];
|
|
rgbout[1] = 65535 - rgbout[1];
|
|
rgbout[2] = 65535 - rgbout[2];
|
|
calc_rgb_to_hsl(rgbout, &h, &s, &v);
|
|
if (ssat < 1)
|
|
s *= ssat;
|
|
else
|
|
{
|
|
double s1 = s * ssat;
|
|
double s2 = 1.0 - ((1.0 - s) * isat);
|
|
s = FMIN(s1, s2);
|
|
}
|
|
if (s > 1)
|
|
s = 1.0;
|
|
calc_hsl_to_rgb(rgbout, h, s, v);
|
|
rgbout[0] = 65535 - rgbout[0];
|
|
rgbout[1] = 65535 - rgbout[1];
|
|
rgbout[2] = 65535 - rgbout[2];
|
|
}
|
|
if (ld < 65536)
|
|
{
|
|
int i;
|
|
for (i = 0; i < 3; i++)
|
|
{
|
|
unsigned t = rgbout[i];
|
|
t = 65535 - (65535 - t) * ld / 65536;
|
|
rgbout[i] = (unsigned short) t;
|
|
}
|
|
}
|
|
o0 = rgbout[0];
|
|
o1 = rgbout[1];
|
|
o2 = rgbout[2];
|
|
}
|
|
rgbin += bpp;
|
|
rgbout += 3;
|
|
width --;
|
|
}
|
|
}
|
|
|
|
static void
|
|
indexed_to_rgb(unsigned char *indexed, /* I - Indexed pixels */
|
|
unsigned short *rgb, /* O - RGB pixels */
|
|
int width, /* I - Width of row */
|
|
int bpp, /* I - Bytes-per-pixel in indexed */
|
|
unsigned char *cmap, /* I - Colormap */
|
|
const vars_t *vars
|
|
)
|
|
{
|
|
rgb_to_rgb(indexed, rgb, width, bpp, cmap, vars);
|
|
}
|
|
|
|
/*
|
|
* 'gray_to_rgb()' - Convert gray image data to RGB.
|
|
*/
|
|
|
|
static void
|
|
gray_to_rgb(unsigned char *grayin, /* I - grayscale pixels */
|
|
unsigned short *rgbout, /* O - RGB pixels */
|
|
int width, /* I - Width of row */
|
|
int bpp, /* I - Bytes/pix in indexed */
|
|
unsigned char *cmap, /* I - Colormap */
|
|
const vars_t *vars
|
|
)
|
|
{
|
|
int use_previous = 0;
|
|
int i0 = -1;
|
|
int i1 = -1;
|
|
int o0 = 0;
|
|
int o1 = 0;
|
|
int o2 = 0;
|
|
lut_t *lut = (lut_t *)(vars->lut);
|
|
while (width > 0)
|
|
{
|
|
unsigned short trgb[3];
|
|
if (bpp == 1)
|
|
{
|
|
/*
|
|
* No alpha in image...
|
|
*/
|
|
if (i0 == grayin[0])
|
|
use_previous = 1;
|
|
else
|
|
{
|
|
use_previous = 0;
|
|
i0 = grayin[0];
|
|
trgb[0] = grayin[0] * 257;
|
|
trgb[1] = grayin[0] * 257;
|
|
trgb[2] = grayin[0] * 257;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (i0 == grayin[0] && i1 == grayin[1])
|
|
use_previous = 1;
|
|
else
|
|
{
|
|
int lookup = (grayin[0] * grayin[1] / 255 + 255 - grayin[1]) *
|
|
257;
|
|
use_previous = 0;
|
|
i0 = grayin[0];
|
|
i1 = grayin[1];
|
|
trgb[0] = lookup;
|
|
trgb[1] = lookup;
|
|
trgb[2] = lookup;
|
|
}
|
|
}
|
|
if (use_previous)
|
|
{
|
|
rgbout[0] = o0;
|
|
rgbout[1] = o1;
|
|
rgbout[2] = o2;
|
|
}
|
|
else
|
|
{
|
|
update_cmyk(trgb);
|
|
rgbout[0] = lookup_value(trgb[0], lut->steps,
|
|
lut->red, lut->shiftval,
|
|
lut->bin_size, lut->bin_shift);
|
|
rgbout[1] = lookup_value(trgb[1], lut->steps,
|
|
lut->green, lut->shiftval,
|
|
lut->bin_size, lut->bin_shift);
|
|
rgbout[2] = lookup_value(trgb[2], lut->steps,
|
|
lut->blue, lut->shiftval,
|
|
lut->bin_size, lut->bin_shift);
|
|
if (vars->saturation != 1.0)
|
|
{
|
|
double t;
|
|
int i;
|
|
for (i = 0; i < 3; i++)
|
|
{
|
|
t = (65535.0 + ((rgbout[i] - 65535.0) * vars->density));
|
|
if (t < 0.0)
|
|
t = 0.0;
|
|
rgbout[i] = t + .5;
|
|
}
|
|
}
|
|
o0 = rgbout[0];
|
|
o1 = rgbout[1];
|
|
o2 = rgbout[2];
|
|
}
|
|
grayin += bpp;
|
|
rgbout += 3;
|
|
width --;
|
|
}
|
|
}
|
|
|
|
static void
|
|
fast_indexed_to_rgb(unsigned char *indexed, /* I - Indexed pixels */
|
|
unsigned short *rgb, /* O - RGB pixels */
|
|
int width, /* I - Width of row */
|
|
int bpp, /* I - Bytes-per-pixel in indexed */
|
|
unsigned char *cmap, /* I - Colormap */
|
|
const vars_t *vars
|
|
)
|
|
{
|
|
int i0 = -1;
|
|
int i1 = -1;
|
|
int o0 = 0;
|
|
int o1 = 0;
|
|
int o2 = 0;
|
|
lut_t *lut = (lut_t *)(vars->lut);
|
|
int use_previous = 0;
|
|
double isat = 1.0;
|
|
if (vars->saturation > 1)
|
|
isat = 1.0 / vars->saturation;
|
|
while (width > 0)
|
|
{
|
|
double h, s, v;
|
|
if (bpp == 1)
|
|
{
|
|
/*
|
|
* No alpha in image...
|
|
*/
|
|
if (i0 == indexed[0])
|
|
use_previous = 1;
|
|
else
|
|
{
|
|
use_previous = 0;
|
|
i0 = indexed[0];
|
|
rgb[0] = lut->red[cmap[i0 * 3 + 0]];
|
|
rgb[1] = lut->green[cmap[i0 * 3 + 1]];
|
|
rgb[2] = lut->blue[cmap[i0 * 3 + 2]];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (i0 == indexed[0] && i1 == indexed[1])
|
|
use_previous = 1;
|
|
else
|
|
{
|
|
use_previous = 0;
|
|
i0 = indexed[0];
|
|
i1 = indexed[1];
|
|
rgb[0] = lut->red[cmap[i0 * 3 + 0] * i1 / 255 + 255 - i1];
|
|
rgb[1] = lut->green[cmap[i0 * 3 + 1] * i1 / 255 + 255 -i1];
|
|
rgb[2] = lut->blue[cmap[i0 * 3 + 2] * i1 / 255 + 255 - i1];
|
|
}
|
|
}
|
|
if (use_previous)
|
|
{
|
|
rgb[0] = o0;
|
|
rgb[1] = o1;
|
|
rgb[2] = o2;
|
|
}
|
|
else
|
|
{
|
|
if (vars->saturation != 1.0)
|
|
{
|
|
calc_rgb_to_hsl(rgb, &h, &s, &v);
|
|
if (vars->saturation < 1)
|
|
s *= vars->saturation;
|
|
else
|
|
{
|
|
double s1 = s * vars->saturation;
|
|
double s2 = 1.0 - ((1.0 - s) * isat);
|
|
s = FMIN(s1, s2);
|
|
}
|
|
if (s > 1)
|
|
s = 1.0;
|
|
calc_hsl_to_rgb(rgb, h, s, v);
|
|
}
|
|
if (vars->density != 1.0)
|
|
{
|
|
double t;
|
|
int i;
|
|
for (i = 0; i < 3; i++)
|
|
{
|
|
t = (65535.0 + ((rgb[i] - 65535.0) * vars->density));
|
|
if (t < 0.0)
|
|
t = 0.0;
|
|
rgb[i] = t + .5;
|
|
}
|
|
}
|
|
o0 = rgb[0];
|
|
o1 = rgb[1];
|
|
o2 = rgb[2];
|
|
}
|
|
indexed += bpp;
|
|
rgb += 3;
|
|
width --;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* 'rgb_to_rgb()' - Convert rgb image data to RGB.
|
|
*/
|
|
|
|
static void
|
|
fast_rgb_to_rgb(unsigned char *rgbin, /* I - RGB pixels */
|
|
unsigned short *rgbout, /* O - RGB pixels */
|
|
int width, /* I - Width of row */
|
|
int bpp, /* I - Bytes/pix in indexed */
|
|
unsigned char *cmap, /* I - Colormap */
|
|
const vars_t *vars
|
|
)
|
|
{
|
|
unsigned ld = vars->density * 65536;
|
|
int i0 = -1;
|
|
int i1 = -1;
|
|
int i2 = -1;
|
|
int i3 = -1;
|
|
int o0 = 0;
|
|
int o1 = 0;
|
|
int o2 = 0;
|
|
lut_t *lut = (lut_t *)(vars->lut);
|
|
int use_previous = 0;
|
|
double isat = 1.0;
|
|
if (vars->saturation > 1)
|
|
isat = 1.0 / vars->saturation;
|
|
while (width > 0)
|
|
{
|
|
double h, s, v;
|
|
if (bpp == 3)
|
|
{
|
|
/*
|
|
* No alpha in image...
|
|
*/
|
|
if (i0 == rgbin[0] && i1 == rgbin[1] && i2 == rgbin[2])
|
|
use_previous = 1;
|
|
else
|
|
{
|
|
use_previous = 0;
|
|
i0 = rgbin[0];
|
|
i1 = rgbin[1];
|
|
i2 = rgbin[2];
|
|
rgbout[0] = lut->red[rgbin[0]];
|
|
rgbout[1] = lut->green[rgbin[1]];
|
|
rgbout[2] = lut->blue[rgbin[2]];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (i0 == rgbin[0] && i1 == rgbin[1] && i2 == rgbin[2] &&
|
|
i3 == rgbin[3])
|
|
use_previous = 1;
|
|
else
|
|
{
|
|
use_previous = 0;
|
|
i0 = rgbin[0];
|
|
i1 = rgbin[1];
|
|
i2 = rgbin[2];
|
|
i3 = rgbin[3];
|
|
rgbout[0] = lut->red[i0 * i3 / 255 + 255 - i3];
|
|
rgbout[1] = lut->green[i1 * i3 / 255 + 255 - i3];
|
|
rgbout[2] = lut->blue[i2 * i3 / 255 + 255 - i3];
|
|
}
|
|
}
|
|
if (use_previous)
|
|
{
|
|
rgbout[0] = o0;
|
|
rgbout[1] = o1;
|
|
rgbout[2] = o2;
|
|
}
|
|
else
|
|
{
|
|
if (vars->saturation != 1.0)
|
|
{
|
|
calc_rgb_to_hsl(rgbout, &h, &s, &v);
|
|
if (vars->saturation < 1)
|
|
s *= vars->saturation;
|
|
else
|
|
{
|
|
double s1 = s * vars->saturation;
|
|
double s2 = 1.0 - ((1.0 - s) * isat);
|
|
s = FMIN(s1, s2);
|
|
}
|
|
if (s > 1)
|
|
s = 1.0;
|
|
calc_hsl_to_rgb(rgbout, h, s, v);
|
|
}
|
|
if (ld < 65536)
|
|
{
|
|
int i;
|
|
for (i = 0; i < 3; i++)
|
|
{
|
|
unsigned t = rgbout[i];
|
|
t = 65535 - (65535 - t) * ld / 65536;
|
|
rgbout[i] = (unsigned short) t;
|
|
}
|
|
}
|
|
o0 = rgbout[0];
|
|
o1 = rgbout[1];
|
|
o2 = rgbout[2];
|
|
}
|
|
rgbin += bpp;
|
|
rgbout += 3;
|
|
width --;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* 'gray_to_rgb()' - Convert gray image data to RGB.
|
|
*/
|
|
|
|
static void
|
|
fast_gray_to_rgb(unsigned char *grayin, /* I - grayscale pixels */
|
|
unsigned short *rgbout, /* O - RGB pixels */
|
|
int width, /* I - Width of row */
|
|
int bpp, /* I - Bytes/pix in indexed */
|
|
unsigned char *cmap, /* I - Colormap */
|
|
const vars_t *vars
|
|
)
|
|
{
|
|
int use_previous = 0;
|
|
int i0 = -1;
|
|
int i1 = -1;
|
|
int o0 = 0;
|
|
int o1 = 0;
|
|
int o2 = 0;
|
|
lut_t *lut = (lut_t *)(vars->lut);
|
|
while (width > 0)
|
|
{
|
|
if (bpp == 1)
|
|
{
|
|
/*
|
|
* No alpha in image...
|
|
*/
|
|
if (i0 == grayin[0])
|
|
use_previous = 1;
|
|
else
|
|
{
|
|
use_previous = 0;
|
|
i0 = grayin[0];
|
|
rgbout[0] = lut->red[grayin[0]];
|
|
rgbout[1] = lut->green[grayin[0]];
|
|
rgbout[2] = lut->blue[grayin[0]];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (i0 == grayin[0] && i1 == grayin[1])
|
|
use_previous = 1;
|
|
else
|
|
{
|
|
int lookup = (grayin[0] * grayin[1] / 255 +
|
|
255 - grayin[1]);
|
|
use_previous = 0;
|
|
i0 = grayin[0];
|
|
i1 = grayin[1];
|
|
rgbout[0] = lut->red[lookup];
|
|
rgbout[1] = lut->green[lookup];
|
|
rgbout[2] = lut->blue[lookup];
|
|
}
|
|
}
|
|
if (use_previous)
|
|
{
|
|
rgbout[0] = o0;
|
|
rgbout[1] = o1;
|
|
rgbout[2] = o2;
|
|
}
|
|
else
|
|
{
|
|
if (vars->density != 1.0)
|
|
{
|
|
double t;
|
|
int i;
|
|
for (i = 0; i < 3; i++)
|
|
{
|
|
t = (65535.0 + ((rgbout[i] - 65535.0) * vars->density));
|
|
if (t < 0.0)
|
|
t = 0.0;
|
|
rgbout[i] = t + .5;
|
|
}
|
|
}
|
|
o0 = rgbout[0];
|
|
o1 = rgbout[1];
|
|
o2 = rgbout[2];
|
|
}
|
|
grayin += bpp;
|
|
rgbout += 3;
|
|
width --;
|
|
}
|
|
}
|
|
|
|
#define ICLAMP(value) \
|
|
do \
|
|
{ \
|
|
if (user->value < min->value) \
|
|
user->value = min->value; \
|
|
else if (user->value > max->value) \
|
|
user->value = max->value; \
|
|
} while (0)
|
|
|
|
void
|
|
merge_printvars(vars_t *user, const vars_t *print)
|
|
{
|
|
const vars_t *max = print_maximum_settings();
|
|
const vars_t *min = print_minimum_settings();
|
|
user->cyan = (user->cyan * print->cyan);
|
|
ICLAMP(cyan);
|
|
user->magenta = (user->magenta * print->magenta);
|
|
ICLAMP(magenta);
|
|
user->yellow = (user->yellow * print->yellow);
|
|
ICLAMP(yellow);
|
|
user->contrast = (user->contrast * print->contrast);
|
|
ICLAMP(contrast);
|
|
user->brightness = (user->brightness * print->brightness);
|
|
ICLAMP(brightness);
|
|
user->gamma /= print->gamma;
|
|
ICLAMP(gamma);
|
|
user->saturation *= print->saturation;
|
|
ICLAMP(saturation);
|
|
user->density *= print->density;
|
|
ICLAMP(density);
|
|
}
|
|
|
|
static lut_t *
|
|
allocate_lut(size_t steps)
|
|
{
|
|
int i;
|
|
lut_t *ret = malloc(sizeof(lut_t));
|
|
ret->steps = steps;
|
|
ret->composite = malloc(sizeof(unsigned short) * steps);
|
|
ret->red = malloc(sizeof(unsigned short) * steps);
|
|
ret->green = malloc(sizeof(unsigned short) * steps);
|
|
ret->blue = malloc(sizeof(unsigned short) * steps);
|
|
ret->shiftval = 0;
|
|
for (i = 1; i < steps; i += i)
|
|
ret->shiftval++;
|
|
ret->bin_size = 65536 / steps;
|
|
ret->bin_shift = 16 - ret->shiftval;
|
|
return ret;
|
|
}
|
|
|
|
void
|
|
free_lut(vars_t *v)
|
|
{
|
|
if (v->lut)
|
|
{
|
|
lut_t *lut = (lut_t *)(v->lut);
|
|
if (lut->composite)
|
|
free(lut->composite);
|
|
if (lut->red)
|
|
free(lut->red);
|
|
if (lut->green)
|
|
free(lut->green);
|
|
if (lut->blue)
|
|
free(lut->blue);
|
|
lut->steps = 0;
|
|
lut->composite = NULL;
|
|
lut->red = NULL;
|
|
lut->green = NULL;
|
|
lut->blue = NULL;
|
|
free(v->lut);
|
|
v->lut = NULL;
|
|
}
|
|
}
|
|
|
|
/* #define PRINT_LUT */
|
|
|
|
void
|
|
compute_lut(size_t steps, vars_t *uv)
|
|
{
|
|
double pixel, /* Pixel value */
|
|
red_pixel, /* Pixel value */
|
|
green_pixel, /* Pixel value */
|
|
blue_pixel; /* Pixel value */
|
|
int i;
|
|
#ifdef PRINT_LUT
|
|
FILE *ltfile = fopen("/mnt1/lut", "w");
|
|
#endif
|
|
/*
|
|
* Got an output file/command, now compute a brightness lookup table...
|
|
*/
|
|
|
|
double cyan = uv->cyan;
|
|
double magenta = uv->magenta;
|
|
double yellow = uv->yellow;
|
|
double print_gamma = uv->gamma;
|
|
double contrast = uv->contrast;
|
|
double app_gamma = uv->app_gamma;
|
|
double brightness = uv->brightness;
|
|
double screen_gamma = app_gamma / 1.7; /* Why 1.7??? */
|
|
lut_t *lut;
|
|
|
|
/*
|
|
* Monochrome mode simply thresholds the input
|
|
* to decide whether to print at all. The printer gamma
|
|
* is intended to represent the analog response of the printer.
|
|
* Using it shifts the threshold, which is not the intent
|
|
* of how this works.
|
|
*/
|
|
if (uv->image_type == IMAGE_MONOCHROME)
|
|
print_gamma = 1.0;
|
|
|
|
uv->lut = allocate_lut(steps);
|
|
lut = (lut_t *)(uv->lut);
|
|
for (i = 0; i < steps; i ++)
|
|
{
|
|
double temp_pixel;
|
|
pixel = (double) i / (double) (steps - 1);
|
|
|
|
/*
|
|
* First, correct contrast
|
|
*/
|
|
if (pixel >= .5)
|
|
temp_pixel = 1.0 - pixel;
|
|
else
|
|
temp_pixel = pixel;
|
|
if (temp_pixel <= .000001 && contrast <= .0001)
|
|
temp_pixel = .5;
|
|
else if (temp_pixel > 1)
|
|
temp_pixel = .5 * pow(2 * temp_pixel, pow(contrast, contrast));
|
|
else if (temp_pixel < 1)
|
|
temp_pixel = 0.5 -
|
|
((0.5 - .5 * pow(2 * temp_pixel, contrast)) * contrast);
|
|
if (temp_pixel > .5)
|
|
temp_pixel = .5;
|
|
else if (temp_pixel < 0)
|
|
temp_pixel = 0;
|
|
if (pixel < .5)
|
|
pixel = temp_pixel;
|
|
else
|
|
pixel = 1 - temp_pixel;
|
|
|
|
/*
|
|
* Second, do brightness
|
|
*/
|
|
if (brightness < 1)
|
|
pixel = pixel * brightness;
|
|
else
|
|
pixel = 1 - ((1 - pixel) * (2 - brightness));
|
|
|
|
/*
|
|
* Third, correct for the screen gamma
|
|
*/
|
|
pixel = 1.0 - pow(pixel, screen_gamma);
|
|
|
|
/*
|
|
* Third, fix up cyan, magenta, yellow values
|
|
*/
|
|
if (pixel < 0.0)
|
|
pixel = 0.0;
|
|
else if (pixel > 1.0)
|
|
pixel = 1.0;
|
|
|
|
if (pixel > .9999 && cyan < .00001)
|
|
red_pixel = 0;
|
|
else
|
|
red_pixel = 1 - pow(1 - pixel, cyan);
|
|
if (pixel > .9999 && magenta < .00001)
|
|
green_pixel = 0;
|
|
else
|
|
green_pixel = 1 - pow(1 - pixel, magenta);
|
|
if (pixel > .9999 && yellow < .00001)
|
|
blue_pixel = 0;
|
|
else
|
|
blue_pixel = 1 - pow(1 - pixel, yellow);
|
|
|
|
/*
|
|
* Finally, fix up print gamma and scale
|
|
*/
|
|
|
|
pixel = 65535 * (1 - pow(pixel, print_gamma)) + .5;
|
|
red_pixel = 65535 * (1 - pow(red_pixel, print_gamma)) + .5;
|
|
green_pixel = 65535 * (1 - pow(green_pixel, print_gamma)) + .5;
|
|
blue_pixel = 65535 * (1 - pow(blue_pixel, print_gamma)) + .5;
|
|
|
|
if (pixel <= 0.0)
|
|
lut->composite[i] = 0;
|
|
else if (pixel >= 65535.0)
|
|
lut->composite[i] = 65535;
|
|
else
|
|
lut->composite[i] = (unsigned)(pixel);
|
|
|
|
if (red_pixel <= 0.0)
|
|
lut->red[i] = 0;
|
|
else if (red_pixel >= 65535.0)
|
|
lut->red[i] = 65535;
|
|
else
|
|
lut->red[i] = (unsigned)(red_pixel);
|
|
|
|
if (green_pixel <= 0.0)
|
|
lut->green[i] = 0;
|
|
else if (green_pixel >= 65535.0)
|
|
lut->green[i] = 65535;
|
|
else
|
|
lut->green[i] = (unsigned)(green_pixel);
|
|
|
|
if (blue_pixel <= 0.0)
|
|
lut->blue[i] = 0;
|
|
else if (blue_pixel >= 65535.0)
|
|
lut->blue[i] = 65535;
|
|
else
|
|
lut->blue[i] = (unsigned)(blue_pixel);
|
|
#ifdef PRINT_LUT
|
|
fprintf(ltfile, "%3i %5d %5d %5d %5d %f %f %f %f %f %f %f %f\n",
|
|
i, lut->composite[i], lut->red[i],
|
|
lut->green[i], lut->blue[i], pixel, red_pixel,
|
|
green_pixel, blue_pixel, print_gamma, screen_gamma,
|
|
print_gamma, app_gamma);
|
|
#endif
|
|
}
|
|
|
|
#ifdef PRINT_LUT
|
|
fclose(ltfile);
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
* 'default_media_size()' - Return the size of a default page size.
|
|
*/
|
|
|
|
/*
|
|
* Sizes are converted to 1/72in, then rounded down so that we don't
|
|
* print off the edge of the paper.
|
|
*/
|
|
const static papersize_t paper_sizes[] =
|
|
{
|
|
/* Common imperial page sizes */
|
|
{ "Letter", 612, 792, PAPERSIZE_ENGLISH }, /* 8.5in x 11in */
|
|
{ "Legal", 612, 1008, PAPERSIZE_ENGLISH }, /* 8.5in x 14in */
|
|
{ "Tabloid", 792, 1224, PAPERSIZE_ENGLISH }, /* 11in x 17in */
|
|
{ "Executive", 522, 756, PAPERSIZE_ENGLISH }, /* 7.25 * 10.5in */
|
|
{ "Postcard", 283, 416, PAPERSIZE_ENGLISH }, /* 100mm x 147mm */
|
|
{ "3x5", 216, 360, PAPERSIZE_ENGLISH },
|
|
{ "4x6", 288, 432, PAPERSIZE_ENGLISH },
|
|
{ "Epson 4x6 Photo Paper", 306, 495, PAPERSIZE_ENGLISH },
|
|
{ "5x7", 360, 504, PAPERSIZE_ENGLISH },
|
|
{ "5x8", 360, 576, PAPERSIZE_ENGLISH },
|
|
{ "HalfLetter", 396, 612, PAPERSIZE_ENGLISH },
|
|
{ "6x8", 432, 576, PAPERSIZE_ENGLISH },
|
|
{ "8x10", 576, 720, PAPERSIZE_ENGLISH },
|
|
{ "Manual", 396, 612, PAPERSIZE_ENGLISH }, /* 5.5in x 8.5in */
|
|
{ "12x18", 864, 1296, PAPERSIZE_ENGLISH },
|
|
{ "13x19", 936, 1368, PAPERSIZE_ENGLISH },
|
|
|
|
/* Other common photographic paper sizes */
|
|
{ "8x12", 576, 864, PAPERSIZE_ENGLISH }, /* Sometimes used for 35 mm */
|
|
{ "11x14", 792, 1008, PAPERSIZE_ENGLISH },
|
|
{ "16x20", 1152, 1440, PAPERSIZE_ENGLISH },
|
|
{ "16x24", 1152, 1728, PAPERSIZE_ENGLISH }, /* 20x24 for 35 mm */
|
|
{ "20x24", 1440, 1728, PAPERSIZE_ENGLISH },
|
|
{ "20x30", 1440, 2160, PAPERSIZE_ENGLISH }, /* 24x30 for 35 mm */
|
|
{ "24x30", 1728, 2160, PAPERSIZE_ENGLISH },
|
|
{ "24x36", 1728, 2592, PAPERSIZE_ENGLISH }, /* Sometimes used for 35 mm */
|
|
{ "30x40", 2160, 2880, PAPERSIZE_ENGLISH },
|
|
|
|
/* International Paper Sizes (mostly taken from BS4000:1968) */
|
|
|
|
/*
|
|
* "A" series: Paper and boards, trimmed sizes
|
|
*
|
|
* "A" sizes are in the ratio 1 : sqrt(2). A0 has a total area
|
|
* of 1 square metre. Everything is rounded to the nearest
|
|
* millimetre. Thus, A0 is 841mm x 1189mm. Every other A
|
|
* size is obtained by doubling or halving another A size.
|
|
*/
|
|
{ "4A", 4768, 6749, PAPERSIZE_METRIC }, /* 1682mm x 2378mm */
|
|
{ "2A", 3370, 4768, PAPERSIZE_METRIC }, /* 1189mm x 1682mm */
|
|
{ "A0", 2384, 3370, PAPERSIZE_METRIC }, /* 841mm x 1189mm */
|
|
{ "A1", 1684, 2384, PAPERSIZE_METRIC }, /* 594mm x 841mm */
|
|
{ "A2", 1191, 1684, PAPERSIZE_METRIC }, /* 420mm x 594mm */
|
|
{ "A3", 842, 1191, PAPERSIZE_METRIC }, /* 297mm x 420mm */
|
|
{ "A4", 595, 842, PAPERSIZE_METRIC }, /* 210mm x 297mm */
|
|
{ "A5", 420, 595, PAPERSIZE_METRIC }, /* 148mm x 210mm */
|
|
{ "A6", 297, 420, PAPERSIZE_METRIC }, /* 105mm x 148mm */
|
|
{ "A7", 210, 297, PAPERSIZE_METRIC }, /* 74mm x 105mm */
|
|
{ "A8", 148, 210, PAPERSIZE_METRIC }, /* 52mm x 74mm */
|
|
{ "A9", 105, 148, PAPERSIZE_METRIC }, /* 37mm x 52mm */
|
|
{ "A10", 73, 105, PAPERSIZE_METRIC }, /* 26mm x 37mm */
|
|
|
|
/*
|
|
* Stock sizes for normal trims.
|
|
* Allowance for trim is 3 millimetres.
|
|
*/
|
|
{ "RA0", 2437, 3458, PAPERSIZE_METRIC }, /* 860mm x 1220mm */
|
|
{ "RA1", 1729, 2437, PAPERSIZE_METRIC }, /* 610mm x 860mm */
|
|
{ "RA2", 1218, 1729, PAPERSIZE_METRIC }, /* 430mm x 610mm */
|
|
{ "RA3", 864, 1218, PAPERSIZE_METRIC }, /* 305mm x 430mm */
|
|
{ "RA4", 609, 864, PAPERSIZE_METRIC }, /* 215mm x 305mm */
|
|
|
|
/*
|
|
* Stock sizes for bled work or extra trims.
|
|
*/
|
|
{ "SRA0", 2551, 3628, PAPERSIZE_METRIC }, /* 900mm x 1280mm */
|
|
{ "SRA1", 1814, 2551, PAPERSIZE_METRIC }, /* 640mm x 900mm */
|
|
{ "SRA2", 1275, 1814, PAPERSIZE_METRIC }, /* 450mm x 640mm */
|
|
{ "SRA3", 907, 1275, PAPERSIZE_METRIC }, /* 320mm x 450mm */
|
|
{ "SRA4", 637, 907, PAPERSIZE_METRIC }, /* 225mm x 320mm */
|
|
|
|
/*
|
|
* "B" series: Posters, wall charts and similar items.
|
|
*/
|
|
{ "4B ISO", 5669, 8016, PAPERSIZE_METRIC }, /* 2000mm x 2828mm */
|
|
{ "2B ISO", 4008, 5669, PAPERSIZE_METRIC }, /* 1414mm x 2000mm */
|
|
{ "B0 ISO", 2834, 4008, PAPERSIZE_METRIC }, /* 1000mm x 1414mm */
|
|
{ "B1 ISO", 2004, 2834, PAPERSIZE_METRIC }, /* 707mm x 1000mm */
|
|
{ "B2 ISO", 1417, 2004, PAPERSIZE_METRIC }, /* 500mm x 707mm */
|
|
{ "B3 ISO", 1000, 1417, PAPERSIZE_METRIC }, /* 353mm x 500mm */
|
|
{ "B4 ISO", 708, 1000, PAPERSIZE_METRIC }, /* 250mm x 353mm */
|
|
{ "B5 ISO", 498, 708, PAPERSIZE_METRIC }, /* 176mm x 250mm */
|
|
{ "B6 ISO", 354, 498, PAPERSIZE_METRIC }, /* 125mm x 176mm */
|
|
{ "B7 ISO", 249, 354, PAPERSIZE_METRIC }, /* 88mm x 125mm */
|
|
{ "B8 ISO", 175, 249, PAPERSIZE_METRIC }, /* 62mm x 88mm */
|
|
{ "B9 ISO", 124, 175, PAPERSIZE_METRIC }, /* 44mm x 62mm */
|
|
{ "B10 ISO", 87, 124, PAPERSIZE_METRIC }, /* 31mm x 44mm */
|
|
|
|
{ "B0 JIS", 2919, 4127, PAPERSIZE_METRIC },
|
|
{ "B1 JIS", 2063, 2919, PAPERSIZE_METRIC },
|
|
{ "B2 JIS", 1459, 2063, PAPERSIZE_METRIC },
|
|
{ "B3 JIS", 1029, 1459, PAPERSIZE_METRIC },
|
|
{ "B4 JIS", 727, 1029, PAPERSIZE_METRIC },
|
|
{ "B5 JIS", 518, 727, PAPERSIZE_METRIC },
|
|
{ "B6 JIS", 362, 518, PAPERSIZE_METRIC },
|
|
{ "B7 JIS", 257, 362, PAPERSIZE_METRIC },
|
|
{ "B8 JIS", 180, 257, PAPERSIZE_METRIC },
|
|
{ "B9 JIS", 127, 180, PAPERSIZE_METRIC },
|
|
{ "B10 JIS", 90, 127, PAPERSIZE_METRIC },
|
|
|
|
/*
|
|
* "C" series: Envelopes or folders suitable for A size stationery.
|
|
*/
|
|
{ "C0", 2599, 3676, PAPERSIZE_METRIC }, /* 917mm x 1297mm */
|
|
{ "C1", 1836, 2599, PAPERSIZE_METRIC }, /* 648mm x 917mm */
|
|
{ "C2", 1298, 1836, PAPERSIZE_METRIC }, /* 458mm x 648mm */
|
|
{ "C3", 918, 1298, PAPERSIZE_METRIC }, /* 324mm x 458mm */
|
|
{ "C4", 649, 918, PAPERSIZE_METRIC }, /* 229mm x 324mm */
|
|
{ "C5", 459, 649, PAPERSIZE_METRIC }, /* 162mm x 229mm */
|
|
{ "B6-C4", 354, 918, PAPERSIZE_METRIC }, /* 125mm x 324mm */
|
|
{ "C6", 323, 459, PAPERSIZE_METRIC }, /* 114mm x 162mm */
|
|
{ "DL", 311, 623, PAPERSIZE_METRIC }, /* 110mm x 220mm */
|
|
{ "C7-6", 229, 459, PAPERSIZE_METRIC }, /* 81mm x 162mm */
|
|
{ "C7", 229, 323, PAPERSIZE_METRIC }, /* 81mm x 114mm */
|
|
{ "C8", 161, 229, PAPERSIZE_METRIC }, /* 57mm x 81mm */
|
|
{ "C9", 113, 161, PAPERSIZE_METRIC }, /* 40mm x 57mm */
|
|
{ "C10", 79, 113, PAPERSIZE_METRIC }, /* 28mm x 40mm */
|
|
|
|
/*
|
|
* US CAD standard paper sizes
|
|
*/
|
|
{ "ArchA", 648, 864, PAPERSIZE_ENGLISH },
|
|
{ "ArchB", 864, 1296, PAPERSIZE_ENGLISH },
|
|
{ "ArchC", 1296, 1728, PAPERSIZE_ENGLISH },
|
|
{ "ArchD", 1728, 2592, PAPERSIZE_ENGLISH },
|
|
{ "ArchE", 2592, 3456, PAPERSIZE_ENGLISH },
|
|
|
|
/*
|
|
* Foolscap
|
|
*/
|
|
{ "flsa", 612, 936, PAPERSIZE_ENGLISH }, /* American foolscap */
|
|
{ "flse", 648, 936, PAPERSIZE_ENGLISH }, /* European foolscap */
|
|
|
|
/*
|
|
* Sizes for book production
|
|
* The BPIF and the Publishers Association jointly recommend ten
|
|
* standard metric sizes for case-bound titles as follows:
|
|
*/
|
|
{ "Crown Quarto", 535, 697, PAPERSIZE_METRIC }, /* 189mm x 246mm */
|
|
{ "Large Crown Quarto", 569, 731, PAPERSIZE_METRIC }, /* 201mm x 258mm */
|
|
{ "Demy Quarto", 620, 782, PAPERSIZE_METRIC }, /* 219mm x 276mm */
|
|
{ "Royal Quarto", 671, 884, PAPERSIZE_METRIC }, /* 237mm x 312mm */
|
|
/*{ "ISO A4", 595, 841, PAPERSIZE_METRIC }, 210mm x 297mm */
|
|
{ "Crown Octavo", 348, 527, PAPERSIZE_METRIC }, /* 123mm x 186mm */
|
|
{ "Large Crown Octavo", 365, 561, PAPERSIZE_METRIC }, /* 129mm x 198mm */
|
|
{ "Demy Octavo", 391, 612, PAPERSIZE_METRIC }, /* 138mm x 216mm */
|
|
{ "Royal Octavo", 442, 663, PAPERSIZE_METRIC }, /* 156mm x 234mm */
|
|
/*{ "ISO A5", 419, 595, PAPERSIZE_METRIC }, 148mm x 210mm */
|
|
|
|
/* Paperback sizes in common usage */
|
|
{ "Small paperback", 314, 504, PAPERSIZE_METRIC }, /* 111mm x 178mm */
|
|
{ "Penguin small paperback", 314, 513, PAPERSIZE_METRIC }, /* 111mm x 181mm */
|
|
{ "Penguin large paperback", 365, 561, PAPERSIZE_METRIC }, /* 129mm x 198mm */
|
|
|
|
/* Miscellaneous sizes */
|
|
{ "Hagaki Card", 283, 420, PAPERSIZE_METRIC }, /* 100 x 148 mm */
|
|
{ "Oufuku Card", 420, 567, PAPERSIZE_METRIC }, /* 148 x 200 mm */
|
|
{ "Long 3", 340, 666, PAPERSIZE_METRIC }, /* Japanese long envelope #3 */
|
|
{ "Long 4", 255, 581, PAPERSIZE_METRIC }, /* Japanese long envelope #4 */
|
|
{ "Kaku", 680, 941, PAPERSIZE_METRIC }, /* Japanese Kaku envelope #4 */
|
|
{ "Commercial 10", 297, 684, PAPERSIZE_ENGLISH }, /* US Commercial 10 env */
|
|
{ "A2 Invitation", 315, 414, PAPERSIZE_ENGLISH }, /* US A2 invitation */
|
|
|
|
{ "", 0, 0, PAPERSIZE_METRIC }
|
|
};
|
|
|
|
int
|
|
known_papersizes(void)
|
|
{
|
|
return sizeof(paper_sizes) / sizeof(papersize_t);
|
|
}
|
|
|
|
const papersize_t *
|
|
get_papersizes(void)
|
|
{
|
|
return paper_sizes;
|
|
}
|
|
|
|
const papersize_t *
|
|
get_papersize_by_name(const char *name)
|
|
{
|
|
const papersize_t *val = &(paper_sizes[0]);
|
|
while (strlen(val->name) > 0)
|
|
{
|
|
if (!strcasecmp(val->name, name))
|
|
return val;
|
|
val++;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
#define IABS(a) ((a) > 0 ? a : -(a))
|
|
|
|
static int
|
|
paper_size_mismatch(int l, int w, const papersize_t *val)
|
|
{
|
|
int hdiff = IABS(l - (int) val->length);
|
|
int vdiff = fabs(w - (int) val->width);
|
|
return hdiff + vdiff;
|
|
}
|
|
|
|
const papersize_t *
|
|
get_papersize_by_size(int l, int w)
|
|
{
|
|
int score = INT_MAX;
|
|
const papersize_t *ref = NULL;
|
|
const papersize_t *val = &(paper_sizes[0]);
|
|
while (strlen(val->name) > 0)
|
|
{
|
|
if (val->width == w && val->length == l)
|
|
return val;
|
|
else
|
|
{
|
|
int myscore = paper_size_mismatch(l, w, val);
|
|
if (myscore < score && myscore < 20)
|
|
{
|
|
ref = val;
|
|
score = myscore;
|
|
}
|
|
}
|
|
val++;
|
|
}
|
|
return ref;
|
|
}
|
|
|
|
void
|
|
default_media_size(const printer_t *printer,
|
|
/* I - Printer model (not used) */
|
|
const vars_t *v, /* I */
|
|
int *width, /* O - Width in points */
|
|
int *length) /* O - Length in points */
|
|
{
|
|
if (v->page_width > 0 && v->page_height > 0)
|
|
{
|
|
*width = v->page_width;
|
|
*length = v->page_height;
|
|
}
|
|
else
|
|
{
|
|
const papersize_t *papersize = get_papersize_by_name(v->media_size);
|
|
if (!papersize)
|
|
{
|
|
*width = 1;
|
|
*length = 1;
|
|
}
|
|
else
|
|
{
|
|
*width = papersize->width;
|
|
*length = papersize->length;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* The list of printers has been moved to printers.c
|
|
*/
|
|
#include "print-printers.c"
|
|
|
|
int
|
|
known_printers(void)
|
|
{
|
|
return printer_count;
|
|
}
|
|
|
|
const printer_t *
|
|
get_printers(void)
|
|
{
|
|
return printers;
|
|
}
|
|
|
|
const printer_t *
|
|
get_printer_by_index(int idx)
|
|
{
|
|
return &(printers[idx]);
|
|
}
|
|
|
|
const printer_t *
|
|
get_printer_by_long_name(const char *long_name)
|
|
{
|
|
const printer_t *val = &(printers[0]);
|
|
int i;
|
|
for (i = 0; i < known_printers(); i++)
|
|
{
|
|
if (!strcmp(val->long_name, long_name))
|
|
return val;
|
|
val++;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
const printer_t *
|
|
get_printer_by_driver(const char *driver)
|
|
{
|
|
const printer_t *val = &(printers[0]);
|
|
int i;
|
|
for (i = 0; i < known_printers(); i++)
|
|
{
|
|
if (!strcmp(val->driver, driver))
|
|
return val;
|
|
val++;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
int
|
|
get_printer_index_by_driver(const char *driver)
|
|
{
|
|
int idx = 0;
|
|
const printer_t *val = &(printers[0]);
|
|
for (idx = 0; idx < known_printers(); idx++)
|
|
{
|
|
if (!strcmp(val->driver, driver))
|
|
return idx;
|
|
val++;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
const char *
|
|
default_dither_algorithm(void)
|
|
{
|
|
return dither_algo_names[0];
|
|
}
|
|
|
|
convert_t
|
|
choose_colorfunc(int output_type,
|
|
int image_bpp,
|
|
const unsigned char *cmap,
|
|
int *out_bpp,
|
|
const vars_t *v)
|
|
{
|
|
if (v->image_type == IMAGE_MONOCHROME)
|
|
{
|
|
*out_bpp = 1;
|
|
|
|
if (image_bpp >= 3)
|
|
return rgb_to_monochrome;
|
|
else if (cmap == NULL)
|
|
return gray_to_monochrome;
|
|
else
|
|
return indexed_to_monochrome;
|
|
}
|
|
else if (output_type == OUTPUT_COLOR)
|
|
{
|
|
*out_bpp = 3;
|
|
|
|
if (image_bpp >= 3)
|
|
{
|
|
if (v->image_type == IMAGE_CONTINUOUS)
|
|
return rgb_to_rgb;
|
|
else
|
|
return fast_rgb_to_rgb;
|
|
}
|
|
else if (cmap == NULL)
|
|
{
|
|
if (v->image_type == IMAGE_CONTINUOUS)
|
|
return gray_to_rgb;
|
|
else
|
|
return fast_gray_to_rgb;
|
|
}
|
|
else
|
|
{
|
|
if (v->image_type == IMAGE_CONTINUOUS)
|
|
return indexed_to_rgb;
|
|
else
|
|
return fast_indexed_to_rgb;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
*out_bpp = 1;
|
|
|
|
if (image_bpp >= 3)
|
|
return rgb_to_gray;
|
|
else if (cmap == NULL)
|
|
return gray_to_gray;
|
|
else
|
|
return indexed_to_gray;
|
|
}
|
|
}
|
|
|
|
void
|
|
compute_page_parameters(int page_right, /* I */
|
|
int page_left, /* I */
|
|
int page_top, /* I */
|
|
int page_bottom, /* I */
|
|
double scaling, /* I */
|
|
int image_width, /* I */
|
|
int image_height, /* I */
|
|
Image image, /* IO */
|
|
int *orientation, /* IO */
|
|
int *page_width, /* O */
|
|
int *page_height, /* O */
|
|
int *out_width, /* O */
|
|
int *out_height, /* O */
|
|
int *left, /* O */
|
|
int *top) /* O */
|
|
{
|
|
*page_width = page_right - page_left;
|
|
*page_height = page_top - page_bottom;
|
|
|
|
/* In AUTO orientation, just orient the paper the same way as the image. */
|
|
|
|
if (*orientation == ORIENT_AUTO)
|
|
{
|
|
if ((*page_width >= *page_height && image_width >= image_height)
|
|
|| (*page_height >= *page_width && image_height >= image_width))
|
|
*orientation = ORIENT_PORTRAIT;
|
|
else
|
|
*orientation = ORIENT_LANDSCAPE;
|
|
}
|
|
|
|
if (*orientation == ORIENT_LANDSCAPE)
|
|
Image_rotate_ccw(image);
|
|
else if (*orientation == ORIENT_UPSIDEDOWN)
|
|
Image_rotate_180(image);
|
|
else if (*orientation == ORIENT_SEASCAPE)
|
|
Image_rotate_cw(image);
|
|
|
|
image_width = Image_width(image);
|
|
image_height = Image_height(image);
|
|
|
|
/*
|
|
* Calculate width/height...
|
|
*/
|
|
|
|
if (scaling == 0.0)
|
|
{
|
|
*out_width = *page_width;
|
|
*out_height = *page_height;
|
|
}
|
|
else if (scaling < 0.0)
|
|
{
|
|
/*
|
|
* Scale to pixels per inch...
|
|
*/
|
|
|
|
*out_width = image_width * -72.0 / scaling;
|
|
*out_height = image_height * -72.0 / scaling;
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* Scale by percent...
|
|
*/
|
|
|
|
/*
|
|
* Decide which orientation gives the proper fit
|
|
* If we ask for 50%, we do not want to exceed that
|
|
* in either dimension!
|
|
*/
|
|
|
|
int twidth0 = *page_width * scaling / 100.0;
|
|
int theight0 = twidth0 * image_height / image_width;
|
|
int theight1 = *page_height * scaling / 100.0;
|
|
int twidth1 = theight1 * image_width / image_height;
|
|
|
|
*out_width = FMIN(twidth0, twidth1);
|
|
*out_height = FMIN(theight0, theight1);
|
|
}
|
|
|
|
if (*out_width == 0)
|
|
*out_width = 1;
|
|
if (*out_height == 0)
|
|
*out_height = 1;
|
|
|
|
/*
|
|
* Adjust offsets depending on the page orientation...
|
|
*/
|
|
|
|
if (*orientation == ORIENT_LANDSCAPE || *orientation == ORIENT_SEASCAPE)
|
|
{
|
|
int x;
|
|
|
|
x = *left;
|
|
*left = *top;
|
|
*top = x;
|
|
}
|
|
|
|
if ((*orientation == ORIENT_UPSIDEDOWN || *orientation == ORIENT_SEASCAPE)
|
|
&& *left >= 0)
|
|
{
|
|
*left = *page_width - *left - *out_width;
|
|
if (*left < 0) {
|
|
*left = 0;
|
|
}
|
|
}
|
|
|
|
if ((*orientation == ORIENT_UPSIDEDOWN || *orientation == ORIENT_LANDSCAPE)
|
|
&& *top >= 0)
|
|
{
|
|
*top = *page_height - *top - *out_height;
|
|
if (*top < 0) {
|
|
*top = 0;
|
|
}
|
|
}
|
|
|
|
if (*left < 0)
|
|
*left = (*page_width - *out_width) / 2;
|
|
|
|
if (*top < 0)
|
|
*top = (*page_height - *out_height) / 2;
|
|
}
|
|
|
|
int
|
|
verify_printer_params(const printer_t *p, const vars_t *v)
|
|
{
|
|
char **vptr;
|
|
int count;
|
|
int i;
|
|
int answer = 1;
|
|
|
|
if (strlen(v->media_size) > 0)
|
|
{
|
|
vptr = (*p->parameters)(p, NULL, "PageSize", &count);
|
|
if (count > 0)
|
|
{
|
|
for (i = 0; i < count; i++)
|
|
if (!strcmp(v->media_size, vptr[i]))
|
|
goto good_page_size;
|
|
answer = 0;
|
|
fprintf(stderr, "%s is not a valid page size\n", v->media_size);
|
|
}
|
|
good_page_size:
|
|
for (i = 0; i < count; i++)
|
|
free(vptr[i]);
|
|
free(vptr);
|
|
}
|
|
else
|
|
{
|
|
int height, width;
|
|
(*p->limit)(p, v, &width, &height);
|
|
#if 0
|
|
fprintf(stderr, "limit %d %d dims %d %d\n", width, height,
|
|
v->page_width, v->page_height);
|
|
#endif
|
|
if (v->page_height <= 0 || v->page_height > height ||
|
|
v->page_width <= 0 || v->page_width > width)
|
|
{
|
|
answer = 0;
|
|
fprintf(stderr, "Image size is not valid\n");
|
|
}
|
|
}
|
|
|
|
if (strlen(v->media_type) > 0)
|
|
{
|
|
vptr = (*p->parameters)(p, NULL, "MediaType", &count);
|
|
if (count > 0)
|
|
{
|
|
for (i = 0; i < count; i++)
|
|
if (!strcmp(v->media_type, vptr[i]))
|
|
goto good_media_type;
|
|
answer = 0;
|
|
fprintf(stderr, "%s is not a valid media type\n", v->media_type);
|
|
}
|
|
good_media_type:
|
|
for (i = 0; i < count; i++)
|
|
free(vptr[i]);
|
|
free(vptr);
|
|
}
|
|
|
|
if (strlen(v->media_source) > 0)
|
|
{
|
|
vptr = (*p->parameters)(p, NULL, "InputSlot", &count);
|
|
if (count > 0)
|
|
{
|
|
for (i = 0; i < count; i++)
|
|
if (!strcmp(v->media_source, vptr[i]))
|
|
goto good_media_source;
|
|
answer = 0;
|
|
fprintf(stderr, "%s is not a valid media source\n", v->media_source);
|
|
}
|
|
good_media_source:
|
|
for (i = 0; i < count; i++)
|
|
free(vptr[i]);
|
|
free(vptr);
|
|
}
|
|
|
|
if (strlen(v->resolution) > 0)
|
|
{
|
|
vptr = (*p->parameters)(p, NULL, "Resolution", &count);
|
|
if (count > 0)
|
|
{
|
|
for (i = 0; i < count; i++)
|
|
if (!strcmp(v->resolution, vptr[i]))
|
|
goto good_resolution;
|
|
answer = 0;
|
|
fprintf(stderr, "%s is not a valid resolution\n", v->resolution);
|
|
}
|
|
good_resolution:
|
|
for (i = 0; i < count; i++)
|
|
free(vptr[i]);
|
|
free(vptr);
|
|
}
|
|
|
|
if (strlen(v->ink_type) > 0)
|
|
{
|
|
vptr = (*p->parameters)(p, NULL, "InkType", &count);
|
|
if (count > 0)
|
|
{
|
|
for (i = 0; i < count; i++)
|
|
if (!strcmp(v->ink_type, vptr[i]))
|
|
goto good_ink_type;
|
|
answer = 0;
|
|
fprintf(stderr, "%s is not a valid ink type\n", v->ink_type);
|
|
}
|
|
good_ink_type:
|
|
for (i = 0; i < count; i++)
|
|
free(vptr[i]);
|
|
free(vptr);
|
|
}
|
|
|
|
for (i = 0; i < num_dither_algos; i++)
|
|
if (!strcmp(v->dither_algorithm, dither_algo_names[i]))
|
|
return answer;
|
|
|
|
fprintf(stderr, "%s is not a valid dither algorithm\n", v->dither_algorithm);
|
|
return 0;
|
|
}
|
|
|
|
const vars_t *
|
|
print_default_settings()
|
|
{
|
|
return &default_vars;
|
|
}
|
|
|
|
const vars_t *
|
|
print_maximum_settings()
|
|
{
|
|
return &max_vars;
|
|
}
|
|
|
|
const vars_t *
|
|
print_minimum_settings()
|
|
{
|
|
return &min_vars;
|
|
}
|
|
|
|
#ifdef QUANTIFY
|
|
unsigned quantify_counts[NUM_QUANTIFY_BUCKETS] = {0};
|
|
struct timeval quantify_buckets[NUM_QUANTIFY_BUCKETS] = {{0,0}};
|
|
int quantify_high_index = 0;
|
|
int quantify_first_time = 1;
|
|
struct timeval quantify_cur_time;
|
|
struct timeval quantify_prev_time;
|
|
|
|
void print_timers()
|
|
{
|
|
int i;
|
|
|
|
printf("Quantify timers:\n");
|
|
for (i = 0; i <= quantify_high_index; i++) {
|
|
if (quantify_counts[i] == 0) continue;
|
|
printf("Bucket %d:\t%ld.%ld s\thit %u times\n", i, quantify_buckets[i].tv_sec, quantify_buckets[i].tv_usec, quantify_counts[i]);
|
|
quantify_buckets[i].tv_sec = 0;
|
|
quantify_buckets[i].tv_usec = 0;
|
|
quantify_counts[i] = 0;
|
|
}
|
|
}
|
|
#endif
|