gimp/plug-ins/print/print-util.c

2212 lines
53 KiB
C
Raw Normal View History

1997-11-25 06:05:25 +08:00
/*
* "$Id$"
*
* Print plug-in driver utility functions for the GIMP.
*
2000-01-27 00:00:48 +08:00
* Copyright 1997-2000 Michael Sweet (mike@easysw.com) and
* Robert Krawitz (rlk@alum.mit.edu)
1997-11-25 06:05:25 +08:00
*
* 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.
1997-11-25 06:05:25 +08:00
*
* Contents:
*
* dither_black() - Dither grayscale pixels to black.
* dither_cmyk() - Dither RGB pixels to cyan, magenta, yellow, and
* black.
* dither_black4() - Dither grayscale pixels to 4 levels of black.
* dither_cmyk4() - Dither RGB pixels to 4 levels of cyan, magenta,
* yellow, and black.
* gray_to_gray() - Convert grayscale image data to grayscale.
* indexed_to_gray() - Convert indexed image data to grayscale.
* indexed_to_rgb() - Convert indexed image data to RGB.
* rgb_to_gray() - Convert RGB image data to grayscale.
* rgb_to_rgb() - Convert RGB image data to RGB.
* default_media_size() - Return the size of a default page size.
1997-11-25 06:05:25 +08:00
*
* Revision History:
*
* See ChangeLog
1997-11-25 06:05:25 +08:00
*/
/* #define PRINT_DEBUG */
1997-11-25 06:05:25 +08:00
#include "print.h"
2000-02-07 23:49:54 +08:00
#include <libgimp/gimp.h>
#include "libgimp/gimpcolorspace.h"
#include <math.h>
1997-11-25 06:05:25 +08:00
/*
* RGB to grayscale luminance constants...
*/
#define LUM_RED 31
#define LUM_GREEN 61
#define LUM_BLUE 8
/*
* Error buffer for dither functions. This needs to be at least 14xMAXDPI
1997-11-25 06:05:25 +08:00
* (currently 720) to avoid problems...
*
* Want to dynamically allocate this so we can save memory!
1997-11-25 06:05:25 +08:00
*/
#define ERROR_ROWS 2
typedef union error
{
struct
{
int c[ERROR_ROWS];
int m[ERROR_ROWS];
int y[ERROR_ROWS];
int k[ERROR_ROWS];
} c;
int v[4][ERROR_ROWS];
} error_t;
error_t *nerror = 0;
int error[2][4][14*2880+1];
1997-11-25 06:05:25 +08:00
/*
* 'dither_black()' - Dither grayscale pixels to black.
*/
void
dither_black(unsigned short *gray, /* I - Grayscale pixels */
int row, /* I - Current Y coordinate */
int src_width, /* I - Width of input row */
int dst_width, /* I - Width of output row */
unsigned char *black) /* O - Black bitmap pixels */
1997-11-25 06:05:25 +08:00
{
int x, /* Current X coordinate */
xerror, /* X error count */
xstep, /* X step */
xmod, /* X error modulus */
length; /* Length of output bitmap in bytes */
unsigned char bit, /* Current bit */
*kptr; /* Current black pixel */
int k, /* Current black error */
ditherk, /* Next error value in buffer */
1997-11-25 06:05:25 +08:00
*kerror0, /* Pointer to current error row */
*kerror1; /* Pointer to next error row */
int ditherbit; /* Random dithering bitmask */
1997-11-25 06:05:25 +08:00
xstep = src_width / dst_width;
xmod = src_width % dst_width;
2000-01-27 00:00:48 +08:00
length = (dst_width + 7) / 8;
1997-11-25 06:05:25 +08:00
1998-05-17 15:16:50 +08:00
kerror0 = error[row & 1][3];
kerror1 = error[1 - (row & 1)][3];
1997-11-25 06:05:25 +08:00
memset(black, 0, length);
for (x = 0, bit = 128, kptr = black, xerror = 0,
ditherbit = rand(), ditherk = *kerror0;
1997-11-25 06:05:25 +08:00
x < dst_width;
x ++, kerror0 ++, kerror1 ++)
{
k = 65535 - *gray + ditherk / 8;
1998-05-17 15:16:50 +08:00
if (k > 32767)
1997-11-25 06:05:25 +08:00
{
*kptr |= bit;
k -= 65535;
}
1997-11-25 06:05:25 +08:00
if (ditherbit & bit)
{
kerror1[0] = 5 * k;
ditherk = kerror0[1] + 3 * k;
}
else
{
kerror1[0] = 3 * k;
ditherk = kerror0[1] + 5 * k;
}
1997-11-25 06:05:25 +08:00
if (bit == 1)
{
kptr ++;
bit = 128;
ditherbit = rand();
1997-11-25 06:05:25 +08:00
}
else
bit >>= 1;
gray += xstep;
xerror += xmod;
if (xerror >= dst_width)
{
xerror -= dst_width;
gray ++;
}
}
1997-11-25 06:05:25 +08:00
}
/*
* 'dither_cmyk6()' - Dither RGB pixels to cyan, magenta, light cyan,
* light magenta, yellow, and black.
*
* Added by Robert Krawitz <rlk@alum.mit.edu> August 30, 1999.
*
* Let's be really aggressive and use a single routine for ALL cmyk dithering,
* including 6 and 7 color.
*
* Note that this is heavily tuned for Epson Stylus Photo printers.
* This should be generalized for other CMYK and CcMmYK printers. All
* of these constants were empirically determined, and are subject to review.
*/
/*
* Ratios of dark to light inks. The darker ink should be DE / NU darker
* than the light ink.
*
* It is essential to be very careful about use of parentheses with these
* macros!
*
* Increasing the denominators results in use of more dark ink. This creates
* more saturated colors.
*/
#define NU_C 1
2000-01-27 00:00:48 +08:00
#define DE_C 1
#define NU_M 1
2000-01-27 00:00:48 +08:00
#define DE_M 1
#define NU_Y 1
2000-01-27 00:00:48 +08:00
#define DE_Y 1
#define I_RATIO_C NU_C / DE_C
#define I_RATIO_C1 NU_C / (DE_C + NU_C)
#define RATIO_C DE_C / NU_C
#define RATIO_C1 (DE_C + NU_C) / NU_C
2000-01-27 00:00:48 +08:00
const static int C_CONST_0 = 65536 * I_RATIO_C1;
const static int C_CONST_1 = 65536 * I_RATIO_C1;
#define I_RATIO_M NU_M / DE_M
#define I_RATIO_M1 NU_M / (DE_M + NU_M)
#define RATIO_M DE_M / NU_M
#define RATIO_M1 (DE_M + NU_M) / NU_M
2000-01-27 00:00:48 +08:00
const static int M_CONST_0 = 65536 * I_RATIO_M1;
const static int M_CONST_1 = 65536 * I_RATIO_M1;
#define I_RATIO_Y NU_Y / DE_Y
#define I_RATIO_Y1 NU_Y / (DE_Y + NU_Y)
#define RATIO_Y DE_Y / NU_Y
#define RATIO_Y1 (DE_Y + NU_Y) / NU_Y
2000-01-27 00:00:48 +08:00
const static int Y_CONST_0 = 65536 * I_RATIO_Y1;
const static int Y_CONST_1 = 65536 * I_RATIO_Y1;
/*
* Lower and upper bounds for mixing CMY with K to produce gray scale.
* Reducing KDARKNESS_LOWER results in more black being used with relatively
* light grays, which causes speckling. Increasing KDARKNESS_UPPER results
* in more CMY being used in dark tones, which results in less pure black.
* Decreasing the gap too much results in sharp crossover and stairstepping.
*/
2000-01-27 00:00:48 +08:00
#define KDARKNESS_LOWER (12 * 256)
#define KDARKNESS_UPPER (128 * 256)
1997-11-25 06:05:25 +08:00
/*
* Randomizing values for deciding when to output a bit. Normally with the
* error diffusion algorithm a bit is not output until the accumulated value
* of the pixel crosses a threshold. This randomizes the threshold, which
* results in fewer obnoxious diagonal jaggies in pale regions. Smaller values
* result in greater randomizing. We use less randomness for black output
* to avoid production of black speckles in light regions.
1997-11-25 06:05:25 +08:00
*/
2000-01-27 00:00:48 +08:00
#define C_RANDOMIZER 0
#define M_RANDOMIZER 0
#define Y_RANDOMIZER 0
#define K_RANDOMIZER 4
#ifdef PRINT_DEBUG
#define UPDATE_COLOR_DBG(r) \
do { \
od##r = dither##r; \
d##r = r; \
} while (0)
#define PRINT_D1(r, R, d1, d2) \
do { \
fprintf(dbg, "Case 4: o" #r " %lld " #r \
" %lld ditherbit" #d1 " %d ditherbit" #d2 " %d " \
"num %lld den %lld test1 %lld test2 %lld\n", \
o##r, r, ditherbit##d1, ditherbit##d2, \
o##r, 65536ll, \
((32767 + (((long long) ditherbit##d2 / 1) - 32768)) * o##r \
/ 65536), \
((o##r - (65536 * I_RATIO_##R##1 * 3 / 4)) * 65536 / \
(65536 - (65536 * I_RATIO_##R##1 * 3 / 4)))); \
} while (0)
#define PRINT_D2(r, R, d1, d2) \
do { \
fprintf(dbg, "Case 1: o" #r " %lld " #r " %lld test %lld\n", o##r, r, \
(32767 + (((long long) ditherbit##d2 / 1) - 32768)) * \
I_RATIO_##R##1); \
} while (0)
2000-01-27 00:00:48 +08:00
#define PRINT_D3(n, r, R, d1, d2) \
do { \
2000-01-27 00:00:48 +08:00
fprintf(dbg, "Case %d: o" #r " %lld " #r \
" %lld ditherbit" #d1 " %d ditherbit" #d2 " %d " \
2000-01-27 00:00:48 +08:00
"num %lld den %lld test1 %lld test2 %lld\n", n, \
o##r, r, ditherbit##d1, ditherbit##d2, \
o##r, 65536ll, \
((32767 + (((long long) ditherbit##d2 / 1) - 32768)) * o##r / \
65536), cutoff); \
} while (0)
#else /* !PRINT_DEBUG */
#define UPDATE_COLOR_DBG(r) do {} while (0)
#define PRINT_D1(r, R, d1, d2) do {} while (0)
#define PRINT_D2(r, R, d1, d2) do {} while (0)
2000-01-27 00:00:48 +08:00
#define PRINT_D3(n, r, R, d1, d2) do {} while (0)
#endif
#define UPDATE_COLOR(r) \
do { \
o##r = r; \
r += dither##r / 8; \
UPDATE_COLOR_DBG(r); \
} while (0)
2000-01-27 00:00:48 +08:00
#define DO_PRINT_COLOR(color) \
do { \
2000-01-27 00:00:48 +08:00
if (color##bits++ == horizontal_overdensity) \
{ \
2000-01-27 00:00:48 +08:00
*color##ptr |= bit; \
color##bits = 1; \
} \
2000-01-27 00:00:48 +08:00
} while(0)
#define PRINT_COLOR(color, r, R, d1, d2) \
do { \
int comp0 = (32767 + ((ditherbit##d2 >> R##_RANDOMIZER) - \
(32768 >> R##_RANDOMIZER))); \
if (!l##color) \
{ \
if (r > comp0) \
{ \
PRINT_D1(r, R, d1, d2); \
DO_PRINT_COLOR(r); \
r -= 65535; \
} \
} \
else \
{ \
int compare = comp0 * I_RATIO_##R##1; \
if (r <= (R##_CONST_1)) \
{ \
if (r > compare) \
{ \
PRINT_D2(r, R, d1, d2); \
DO_PRINT_COLOR(l##r); \
r -= R##_CONST_0; \
} \
} \
else if (r > compare) \
{ \
int cutoff = ((density - R##_CONST_1) * 65536 / \
(65536 - R##_CONST_1)); \
long long sub; \
if (cutoff >= 0) \
sub = R##_CONST_0 + (((65535ll - R##_CONST_0) * cutoff) >> 16); \
else \
sub = R##_CONST_0 + ((65535ll - R##_CONST_0) * cutoff / 65536); \
if (ditherbit##d1 > cutoff) \
{ \
PRINT_D3(3, r, R, d1, d2); \
DO_PRINT_COLOR(l##r); \
} \
else \
{ \
PRINT_D3(4, r, R, d1, d2); \
DO_PRINT_COLOR(r); \
} \
if (sub < R##_CONST_0) \
r -= R##_CONST_0; \
else if (sub > 65535) \
r -= 65535; \
else \
r -= sub; \
} \
} \
} while (0)
#if 1
#define UPDATE_DITHER(r, d2, x, width) \
do { \
int offset = (15 - (((o##r & 0xf000) >> 12)) * horizontal_overdensity) \
>> 1; \
if (x < offset) \
offset = x; \
else if (x > dst_width - offset - 1) \
offset = dst_width - x - 1; \
if (ditherbit##d2 & bit) \
{ \
r##error1[-offset] += r; \
r##error1[0] += 3 * r; \
r##error1[offset] += r; \
dither##r = r##error0[direction] + 3 * r; \
} \
else \
{ \
r##error1[-offset] += r; \
r##error1[0] += r; \
r##error1[offset] += r; \
dither##r = r##error0[direction] + 5 * r; \
} \
} while (0)
#else
2000-01-27 00:00:48 +08:00
#define UPDATE_DITHER(r, d2, x, width) \
do { \
if (ditherbit##d2 & bit) \
{ \
r##error1[0] = 5 * r; \
dither##r = r##error0[direction] + 3 * r; \
} \
else \
{ \
r##error1[0] = 3 * r; \
dither##r = r##error0[direction] + 5 * r; \
} \
} while (0)
#endif
1997-11-25 06:05:25 +08:00
void
dither_cmyk(unsigned short *rgb, /* I - RGB pixels */
int row, /* I - Current Y coordinate */
int src_width, /* I - Width of input row */
int dst_width, /* I - Width of output rows */
unsigned char *cyan, /* O - Cyan bitmap pixels */
unsigned char *lcyan, /* O - Light cyan bitmap pixels */
unsigned char *magenta, /* O - Magenta bitmap pixels */
unsigned char *lmagenta, /* O - Light magenta bitmap pixels */
unsigned char *yellow, /* O - Yellow bitmap pixels */
unsigned char *lyellow, /* O - Light yellow bitmap pixels */
unsigned char *black, /* O - Black bitmap pixels */
int horizontal_overdensity)
1997-11-25 06:05:25 +08:00
{
int x, /* Current X coordinate */
xerror, /* X error count */
xstep, /* X step */
xmod, /* X error modulus */
length; /* Length of output bitmap in bytes */
long long c, m, y, k, /* CMYK values */
oc, om, ok, oy,
divk; /* Inverse of K */
long long diff; /* Average color difference */
1997-11-25 06:05:25 +08:00
unsigned char bit, /* Current bit */
*cptr, /* Current cyan pixel */
*mptr, /* Current magenta pixel */
*yptr, /* Current yellow pixel */
*lmptr, /* Current light magenta pixel */
*lcptr, /* Current light cyan pixel */
*lyptr, /* Current light yellow pixel */
1997-11-25 06:05:25 +08:00
*kptr; /* Current black pixel */
int ditherc, /* Next error value in buffer */
1997-11-25 06:05:25 +08:00
*cerror0, /* Pointer to current error row */
*cerror1; /* Pointer to next error row */
int dithery, /* Next error value in buffer */
1997-11-25 06:05:25 +08:00
*yerror0, /* Pointer to current error row */
*yerror1; /* Pointer to next error row */
int ditherm, /* Next error value in buffer */
1997-11-25 06:05:25 +08:00
*merror0, /* Pointer to current error row */
*merror1; /* Pointer to next error row */
int ditherk, /* Next error value in buffer */
1997-11-25 06:05:25 +08:00
*kerror0, /* Pointer to current error row */
*kerror1; /* Pointer to next error row */
int ditherbit; /* Random dither bitmask */
int nk;
int ck;
int bk;
int ub, lb;
int ditherbit0, ditherbit1, ditherbit2, ditherbit3;
long long density;
/*
* If horizontal_overdensity is > 1, we want to output a bit only so many
* times that a bit would be generated. These serve as counters for making
* that decision. We make these variable static rather than reinitializing
* at zero each line to avoid having a line of bits near the edge of the
* image.
*/
2000-01-27 00:00:48 +08:00
static int cbits = 1;
static int mbits = 1;
static int ybits = 1;
static int kbits = 1;
static int lcbits = 1;
static int lmbits = 1;
static int lybits = 1;
int overdensity_bits = 0;
#ifdef PRINT_DEBUG
long long odk, odc, odm, ody, dk, dc, dm, dy, xk, xc, xm, xy, yc, ym, yy;
FILE *dbg;
#endif
1997-11-25 06:05:25 +08:00
2000-01-27 00:00:48 +08:00
int terminate;
int direction = row & 1 ? 1 : -1;
switch (horizontal_overdensity)
{
case 0:
case 1:
overdensity_bits = 0;
break;
case 2:
overdensity_bits = 1;
break;
case 4:
overdensity_bits = 2;
break;
case 8:
overdensity_bits = 3;
break;
}
bit = (direction == 1) ? 128 : 1 << (7 - ((dst_width - 1) & 7));
x = (direction == 1) ? 0 : dst_width - 1;
terminate = (direction == 1) ? dst_width : -1;
1997-11-25 06:05:25 +08:00
xstep = 3 * (src_width / dst_width);
xmod = src_width % dst_width;
length = (dst_width + 7) / 8;
1998-05-17 15:16:50 +08:00
cerror0 = error[row & 1][0];
cerror1 = error[1 - (row & 1)][0];
1997-11-25 06:05:25 +08:00
1998-05-17 15:16:50 +08:00
merror0 = error[row & 1][1];
merror1 = error[1 - (row & 1)][1];
1997-11-25 06:05:25 +08:00
1998-05-17 15:16:50 +08:00
yerror0 = error[row & 1][2];
yerror1 = error[1 - (row & 1)][2];
1997-11-25 06:05:25 +08:00
1998-05-17 15:16:50 +08:00
kerror0 = error[row & 1][3];
kerror1 = error[1 - (row & 1)][3];
2000-01-27 00:00:48 +08:00
memset(kerror1, 0, dst_width * sizeof(int));
memset(cerror1, 0, dst_width * sizeof(int));
memset(merror1, 0, dst_width * sizeof(int));
memset(yerror1, 0, dst_width * sizeof(int));
cptr = cyan;
mptr = magenta;
yptr = yellow;
lcptr = lcyan;
lmptr = lmagenta;
lyptr = lyellow;
kptr = black;
xerror = 0;
if (direction == -1)
{
cerror0 += dst_width - 1;
cerror1 += dst_width - 1;
merror0 += dst_width - 1;
merror1 += dst_width - 1;
yerror0 += dst_width - 1;
yerror1 += dst_width - 1;
kerror0 += dst_width - 1;
kerror1 += dst_width - 1;
cptr = cyan + length - 1;
if (lcptr)
lcptr = lcyan + length - 1;
mptr = magenta + length - 1;
if (lmptr)
lmptr = lmagenta + length - 1;
yptr = yellow + length - 1;
if (lyptr)
lyptr = lyellow + length - 1;
if (kptr)
kptr = black + length - 1;
xstep = -xstep;
rgb += 3 * (src_width - 1);
xerror = ((dst_width - 1) * xmod) % dst_width;
xmod = -xmod;
}
1997-11-25 06:05:25 +08:00
memset(cyan, 0, length);
if (lcyan)
memset(lcyan, 0, length);
1997-11-25 06:05:25 +08:00
memset(magenta, 0, length);
if (lmagenta)
memset(lmagenta, 0, length);
1997-11-25 06:05:25 +08:00
memset(yellow, 0, length);
if (lyellow)
memset(lyellow, 0, length);
if (black)
1997-11-25 06:05:25 +08:00
memset(black, 0, length);
#ifdef PRINT_DEBUG
dbg = fopen("/mnt1/dbg", "a");
#endif
/*
* Main loop starts here!
*/
2000-01-27 00:00:48 +08:00
for (ditherbit = rand(),
ditherc = cerror0[0], ditherm = merror0[0], dithery = yerror0[0],
ditherk = kerror0[0],
ditherbit0 = ditherbit & 0xffff,
ditherbit1 = ((ditherbit >> 8) & 0xffff),
ditherbit2 = (((ditherbit >> 16) & 0x7fff) +
((ditherbit & 0x100) << 7)),
ditherbit3 = (((ditherbit >> 24) & 0x7f) + ((ditherbit & 1) << 7) +
((ditherbit >> 8) & 0xff00));
2000-01-27 00:00:48 +08:00
x != terminate;
x += direction,
cerror0 += direction,
cerror1 += direction,
merror0 += direction,
merror1 += direction,
yerror0 += direction,
yerror1 += direction,
kerror0 += direction,
kerror1 += direction)
1997-11-25 06:05:25 +08:00
{
/*
* First compute the standard CMYK separation color values...
*/
int maxlevel;
int ak;
int kdarkness;
c = 65535 - (unsigned) rgb[0];
m = 65535 - (unsigned) rgb[1];
y = 65535 - (unsigned) rgb[2];
oc = c;
om = m;
oy = y;
k = MIN(c, MIN(m, y));
#ifdef PRINT_DEBUG
xc = c;
xm = m;
xy = y;
xk = k;
yc = c;
ym = m;
yy = y;
#endif
maxlevel = MAX(c, MAX(m, y));
1997-11-25 06:05:25 +08:00
if (black != NULL)
{
/*
* Since we're printing black, adjust the black level based upon
* the amount of color in the pixel (colorful pixels get less black)...
*/
2000-01-27 00:00:48 +08:00
int xdiff = (abs(c - m) + abs(c - y) + abs(m - y)) / 3;
diff = 65536 - xdiff;
2000-01-27 00:00:48 +08:00
diff = (diff * diff * diff) >> 32; /* diff = diff^3 */
diff--;
if (diff < 0)
diff = 0;
2000-01-27 00:00:48 +08:00
k = (diff * k) >> 16;
ak = k;
divk = 65535 - k;
if (divk == 0)
c = m = y = 0; /* Grayscale */
else
1997-11-25 06:05:25 +08:00
{
/*
* Full color; update the CMY values for the black value and reduce
* CMY as necessary to give better blues, greens, and reds... :)
*/
2000-01-27 00:00:48 +08:00
c = (65535 - ((rgb[2] + rgb[1]) >> 3)) * (c - k) / divk;
m = (65535 - ((rgb[1] + rgb[0]) >> 3)) * (m - k) / divk;
y = (65535 - ((rgb[0] + rgb[2]) >> 3)) * (y - k) / divk;
}
#ifdef PRINT_DEBUG
yc = c;
ym = m;
yy = y;
#endif
/*
* kdarkness is an artificially computed darkness value for deciding
* how much black vs. CMY to use for the k component. This is
* empirically determined.
*/
ok = k;
nk = k + (ditherk) / 8;
2000-01-27 00:00:48 +08:00
kdarkness = MAX((c + ((c + c + c) >> 3) + m +
((y + y + y + y + y) >> 3)) >> 2, ak);
if (kdarkness < KDARKNESS_UPPER)
{
int rb;
ub = KDARKNESS_UPPER;
lb = KDARKNESS_LOWER;
rb = ub - lb;
#ifdef PRINT_DEBUG
fprintf(dbg, "Black: kd %d ub %d lb %d rb %d test %d range %d\n",
kdarkness, ub, lb, rb, ditherbit % rb, kdarkness - lb);
#endif
if (kdarkness <= lb)
{
bk = 0;
ub = 0;
lb = 1;
}
else if (kdarkness < ub)
{
if (rb == 0 || (ditherbit % rb) < (kdarkness - lb))
bk = nk;
else
bk = 0;
}
else
{
ub = 1;
lb = 1;
bk = nk;
}
}
else
{
#ifdef PRINT_DEBUG
fprintf(dbg, "Black real\n");
#endif
bk = nk;
}
ck = nk - bk;
/*
* These constants are empirically determined to produce a CMY value
* that looks reasonably gray and is reasonably well balanced tonally
* with black. As usual, this is very ad hoc and needs to be
* generalized.
*/
if (lmagenta)
{
2000-01-27 00:00:48 +08:00
int addon = 2 * ck;
c += addon;
m += addon;
y += addon;
}
else
{
c += ck;
m += ck;
y += ck;
}
/*
* Don't allow cmy to grow without bound.
*/
if (c > 65535)
c = 65535;
if (m > 65535)
m = 65535;
if (y > 65535)
y = 65535;
k = bk;
#ifdef PRINT_DEBUG
odk = ditherk;
dk = k;
#endif
2000-01-27 00:00:48 +08:00
if (k > (32767 + ((ditherbit0 >> K_RANDOMIZER) -
(32768 >> K_RANDOMIZER))))
{
2000-01-27 00:00:48 +08:00
DO_PRINT_COLOR(k);
k -= 65535;
}
UPDATE_DITHER(k, 1, x, src_width);
}
else
{
/*
* We're not printing black, but let's adjust the CMY levels to produce
* better reds, greens, and blues...
*/
ok = 0;
c = (65535 - rgb[1] / 4) * (c - k) / 65535 + k;
m = (65535 - rgb[2] / 4) * (m - k) / 65535 + k;
y = (65535 - rgb[0] / 4) * (y - k) / 65535 + k;
}
1997-11-25 06:05:25 +08:00
2000-01-27 00:00:48 +08:00
density = (c + m + y) >> overdensity_bits;
UPDATE_COLOR(c);
UPDATE_COLOR(m);
UPDATE_COLOR(y);
2000-01-27 00:00:48 +08:00
density += (c + m + y) >> overdensity_bits;
/* density >>= 1; */
2000-01-27 00:00:48 +08:00
if (!kptr || !(*kptr & bit))
{
PRINT_COLOR(cyan, c, C, 1, 2);
PRINT_COLOR(magenta, m, M, 2, 3);
PRINT_COLOR(yellow, y, Y, 3, 0);
}
2000-01-27 00:00:48 +08:00
UPDATE_DITHER(c, 2, x, dst_width);
UPDATE_DITHER(m, 3, x, dst_width);
UPDATE_DITHER(y, 0, x, dst_width);
/*****************************************************************
* Advance the loop
*****************************************************************/
#ifdef PRINT_DEBUG
fprintf(dbg, " x %d y %d r %d g %d b %d xc %lld xm %lld xy %lld yc "
"%lld ym %lld yy %lld xk %lld diff %lld divk %lld oc %lld om "
"%lld oy %lld ok %lld c %lld m %lld y %lld k %lld %c%c%c%c%c%c%c"
" dk %lld dc %lld dm %lld dy %lld kd %d ck %d bk %d nk %d ub %d "
"lb %d\n",
x, row,
rgb[0], rgb[1], rgb[2],
xc, xm, xy, yc, ym, yy, xk, diff, divk,
oc, om, oy, ok,
dc, dm, dy, dk,
(*cptr & bit) ? 'c' : ' ',
(lcyan && (*lcptr & bit)) ? 'C' : ' ',
(*mptr & bit) ? 'm' : ' ',
(lmagenta && (*lmptr & bit)) ? 'M' : ' ',
(*yptr & bit) ? 'y' : ' ',
(lyellow && (*lyptr & bit)) ? 'Y' : ' ',
(black && (*kptr & bit)) ? 'k' : ' ',
odk, odc, odm, ody,
kdarkness, ck, bk, nk, ub, lb);
2000-01-27 00:00:48 +08:00
fprintf(dbg, "x %d dir %d c %x %x m %x %x y %x %x k %x %x rgb %x bit %x\n",
x, direction, cptr, cyan, mptr, magenta, yptr, yellow, kptr, black,
rgb, bit);
#endif
2000-01-27 00:00:48 +08:00
ditherbit = rand();
ditherbit0 = ditherbit & 0xffff;
ditherbit1 = ((ditherbit >> 8) & 0xffff);
ditherbit2 = ((ditherbit >> 16) & 0x7fff) + ((ditherbit & 0x100) << 7);
ditherbit3 = ((ditherbit >> 24) & 0x7f) + ((ditherbit & 1) << 7) +
((ditherbit >> 8) & 0xff00);
if (direction == 1)
{
2000-01-27 00:00:48 +08:00
if (bit == 1)
{
cptr ++;
if (lcptr)
lcptr ++;
mptr ++;
if (lmptr)
lmptr ++;
yptr ++;
if (lyptr)
lyptr ++;
if (kptr)
kptr ++;
bit = 128;
}
else
bit >>= 1;
}
else
{
2000-01-27 00:00:48 +08:00
if (bit == 128)
{
cptr --;
if (lcptr)
lcptr --;
mptr --;
if (lmptr)
lmptr --;
yptr --;
if (lyptr)
lyptr --;
if (kptr)
kptr --;
bit = 1;
}
else
bit <<= 1;
}
1997-11-25 06:05:25 +08:00
rgb += xstep;
xerror += xmod;
if (xerror >= dst_width)
2000-01-27 00:00:48 +08:00
{
xerror -= dst_width;
rgb += 3 * direction;
}
else if (xerror < 0)
{
xerror += dst_width;
rgb += 3 * direction;
}
}
/*
* Main loop ends here!
*/
#ifdef PRINT_DEBUG
fprintf(dbg, "\n");
fclose(dbg);
#endif
}
1997-11-25 06:05:25 +08:00
/*
* Constants for 4-level dithering functions...
* NOTE that these constants are HP-specific!
*/
#define LEVEL_3 65535
#define LEVEL_2 (213 * 65536)
#define LEVEL_1 32767
#define LEVEL_0 0
/*
* 'dither_black4()' - Dither grayscale pixels to 4 levels of black.
*/
void
dither_black4(unsigned short *gray, /* I - Grayscale pixels */
int row, /* I - Current Y coordinate */
int src_width, /* I - Width of input row */
int dst_width, /* I - Width of output rows */
unsigned char *black) /* O - Black bitmap pixels */
{
int x, /* Current X coordinate */
xerror, /* X error count */
xstep, /* X step */
xmod, /* X error modulus */
length; /* Length of output bitmap in bytes */
unsigned char bit, /* Current bit */
*kptr; /* Current black pixel */
int k, /* Current black value */
ditherk, /* Next error value in buffer */
*kerror0, /* Pointer to current error row */
*kerror1; /* Pointer to next error row */
int ditherbit; /* Random dither bitmask */
xstep = src_width / dst_width;
xmod = src_width % dst_width;
length = (dst_width + 7) / 8;
kerror0 = error[row & 1][3];
kerror1 = error[1 - (row & 1)][3];
memset(black, 0, length * 2);
for (x = 0, bit = 128, kptr = black, xerror = 0, ditherbit = rand(),
ditherk = kerror0[0];
x < dst_width;
x ++, kerror0 ++, kerror1 ++)
{
k = 65535 - *gray + ditherk / 8;
if (k > ((LEVEL_2 + LEVEL_3) / 2))
{
kptr[0] |= bit;
kptr[length] |= bit;
k -= LEVEL_3;
}
else if (k > ((LEVEL_1 + LEVEL_2) / 2))
{
kptr[length] |= bit;
k -= LEVEL_2;
}
else if (k > ((LEVEL_0 + LEVEL_1) / 2))
1997-11-25 06:05:25 +08:00
{
kptr[0] |= bit;
k -= LEVEL_1;
}
1997-11-25 06:05:25 +08:00
if (ditherbit & bit)
{
kerror1[0] = 5 * k;
ditherk = kerror0[1] + 3 * k;
}
else
{
kerror1[0] = 3 * k;
ditherk = kerror0[1] + 5 * k;
}
1997-11-25 06:05:25 +08:00
if (bit == 1)
{
kptr ++;
bit = 128;
ditherbit = rand();
1997-11-25 06:05:25 +08:00
}
else
bit >>= 1;
gray += xstep;
1997-11-25 06:05:25 +08:00
xerror += xmod;
if (xerror >= dst_width)
{
xerror -= dst_width;
gray ++;
}
}
1997-11-25 06:05:25 +08:00
}
/*
* 'dither_cmyk4()' - Dither RGB pixels to 4 levels of cyan, magenta, yellow,
* and black.
1997-11-25 06:05:25 +08:00
*/
void
dither_cmyk4(unsigned short *rgb, /* I - RGB pixels */
int row, /* I - Current Y coordinate */
int src_width, /* I - Width of input row */
int dst_width, /* I - Width of output rows */
unsigned char *cyan, /* O - Cyan bitmap pixels */
unsigned char *magenta, /* O - Magenta bitmap pixels */
unsigned char *yellow, /* O - Yellow bitmap pixels */
unsigned char *black) /* O - Black bitmap pixels */
1997-11-25 06:05:25 +08:00
{
int x, /* Current X coordinate */
xerror, /* X error count */
xstep, /* X step */
xmod, /* X error modulus */
length; /* Length of output bitmap in bytes */
long long c, m, y, k, /* CMYK values */
divk, /* Inverse of K */
diff; /* Average color difference */
unsigned char bit, /* Current bit */
*cptr, /* Current cyan pixel */
*mptr, /* Current magenta pixel */
*yptr, /* Current yellow pixel */
*kptr; /* Current black pixel */
int ditherc, /* Next error value in buffer */
*cerror0, /* Pointer to current error row */
*cerror1; /* Pointer to next error row */
int dithery, /* Next error value in buffer */
*yerror0, /* Pointer to current error row */
*yerror1; /* Pointer to next error row */
int ditherm, /* Next error value in buffer */
*merror0, /* Pointer to current error row */
*merror1; /* Pointer to next error row */
int ditherk, /* Next error value in buffer */
*kerror0, /* Pointer to current error row */
*kerror1; /* Pointer to next error row */
int ditherbit; /* Random dither bitmask */
1997-11-25 06:05:25 +08:00
xstep = 3 * (src_width / dst_width);
xmod = src_width % dst_width;
length = (dst_width + 7) / 8;
cerror0 = error[row & 1][0];
cerror1 = error[1 - (row & 1)][0];
merror0 = error[row & 1][1];
merror1 = error[1 - (row & 1)][1];
yerror0 = error[row & 1][2];
yerror1 = error[1 - (row & 1)][2];
kerror0 = error[row & 1][3];
kerror1 = error[1 - (row & 1)][3];
memset(cyan, 0, length * 2);
memset(magenta, 0, length * 2);
memset(yellow, 0, length * 2);
memset(black, 0, length * 2);
for (x = 0, bit = 128, cptr = cyan, mptr = magenta, yptr = yellow,
kptr = black, xerror = 0, ditherbit = rand(), ditherc = cerror0[0],
ditherm = merror0[0], dithery = yerror0[0], ditherk = kerror0[0];
x < dst_width;
x ++, cerror0 ++, cerror1 ++, merror0 ++, merror1 ++, yerror0 ++,
yerror1 ++, kerror0 ++, kerror1 ++)
{
/*
* First compute the standard CMYK separation color values...
*/
c = 65535 - rgb[0];
m = 65535 - rgb[1];
y = 65535 - rgb[2];
k = MIN(c, MIN(m, y));
/*
* Since we're printing black, adjust the black level based upon
* the amount of color in the pixel (colorful pixels get less black)...
*/
diff = 65536 - (abs(c - m) + abs(c - y) + abs(m - y)) / 3;
diff = diff * diff * diff / (65536ll * 65536ll); /* diff = diff^3 */
diff--;
k = diff * k / 65535ll;
divk = 65535 - k;
if (divk == 0)
c = m = y = 0; /* Grayscale */
else
{
/*
* Full color; update the CMY values for the black value and reduce
* CMY as necessary to give better blues, greens, and reds... :)
*/
c = (65535 - rgb[1] / 4) * (c - k) / divk;
m = (65535 - rgb[2] / 4) * (m - k) / divk;
y = (65535 - rgb[0] / 4) * (y - k) / divk;
}
k += ditherk / 8;
if (k > ((LEVEL_2 + LEVEL_3) / 2))
{
kptr[0] |= bit;
kptr[length] |= bit;
k -= LEVEL_3;
}
else if (k > ((LEVEL_1 + LEVEL_2) / 2))
{
kptr[length] |= bit;
k -= LEVEL_2;
}
else if (k > ((LEVEL_0 + LEVEL_1) / 2))
{
kptr[0] |= bit;
k -= LEVEL_1;
}
if (ditherbit & bit)
{
kerror1[0] = 5 * k;
ditherk = kerror0[1] + 3 * k;
}
else
{
kerror1[0] = 3 * k;
ditherk = kerror0[1] + 5 * k;
}
c += ditherc / 8;
if (c > ((LEVEL_2 + LEVEL_3) / 2))
{
cptr[0] |= bit;
cptr[length] |= bit;
c -= LEVEL_3;
}
else if (c > ((LEVEL_1 + LEVEL_2) / 2))
{
cptr[length] |= bit;
c -= LEVEL_2;
}
else if (c > ((LEVEL_0 + LEVEL_1) / 2))
{
cptr[0] |= bit;
c -= LEVEL_1;
}
if (ditherbit & bit)
{
cerror1[0] = 5 * c;
ditherc = cerror0[1] + 3 * c;
}
else
{
cerror1[0] = 3 * c;
ditherc = cerror0[1] + 5 * c;
}
m += ditherm / 8;
if (m > ((LEVEL_2 + LEVEL_3) / 2))
{
mptr[0] |= bit;
mptr[length] |= bit;
m -= LEVEL_3;
}
else if (m > ((LEVEL_1 + LEVEL_2) / 2))
{
mptr[length] |= bit;
m -= LEVEL_2;
}
else if (m > ((LEVEL_0 + LEVEL_1) / 2))
{
mptr[0] |= bit;
m -= LEVEL_1;
}
if (ditherbit & bit)
{
merror1[0] = 5 * m;
ditherm = merror0[1] + 3 * m;
}
else
{
merror1[0] = 3 * m;
ditherm = merror0[1] + 5 * m;
}
y += dithery / 8;
if (y > ((LEVEL_2 + LEVEL_3) / 2))
{
yptr[0] |= bit;
yptr[length] |= bit;
y -= LEVEL_3;
}
else if (y > ((LEVEL_1 + LEVEL_2) / 2))
{
yptr[length] |= bit;
y -= LEVEL_2;
}
else if (y > ((LEVEL_0 + LEVEL_1) / 2))
{
yptr[0] |= bit;
y -= LEVEL_1;
}
if (ditherbit & bit)
{
yerror1[0] = 5 * y;
dithery = yerror0[1] + 3 * y;
}
else
{
yerror1[0] = 3 * y;
dithery = yerror0[1] + 5 * y;
}
if (bit == 1)
{
cptr ++;
mptr ++;
yptr ++;
kptr ++;
bit = 128;
ditherbit = rand();
}
else
bit >>= 1;
rgb += xstep;
xerror += xmod;
if (xerror >= dst_width)
{
xerror -= dst_width;
rgb += 3;
}
}
}
/*
* 'gray_to_gray()' - Convert grayscale image data to grayscale (brightness
* adjusted).
*/
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 */
lut_t *lut, /* I - Brightness lookup table */
unsigned char *cmap, /* I - Colormap (unused) */
vars_t *vars
)
{
if (bpp == 1)
{
/*
* No alpha in image...
*/
while (width > 0)
{
*grayout = lut->composite[*grayin];
grayin ++;
grayout ++;
width --;
}
}
else
{
/*
* Handle alpha in image...
*/
while (width > 0)
{
*grayout = lut->composite[grayin[0] * grayin[1] / 255] + 255 - grayin[1];
grayin += bpp;
grayout ++;
width --;
}
}
1997-11-25 06:05:25 +08:00
}
/*
* 'indexed_to_gray()' - Convert indexed image data to grayscale.
*/
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 */
lut_t *lut, /* I - Brightness LUT */
unsigned char *cmap, /* I - Colormap */
vars_t *vars /* I - Saturation */
)
1997-11-25 06:05:25 +08:00
{
int i; /* Looping var */
unsigned char gray_cmap[256]; /* Grayscale colormap */
for (i = 0; i < 256; i ++, cmap += 3)
gray_cmap[i] = (cmap[0] * LUM_RED +
cmap[1] * LUM_GREEN +
cmap[2] * LUM_BLUE) / 100;
if (bpp == 1)
{
/*
* No alpha in image...
*/
1997-11-25 06:05:25 +08:00
while (width > 0)
{
*gray = lut->composite[gray_cmap[*indexed]];
indexed ++;
gray ++;
width --;
}
}
else
1997-11-25 06:05:25 +08:00
{
/*
* Handle alpha in image...
*/
while (width > 0)
{
*gray = lut->composite[gray_cmap[indexed[0] * indexed[1] / 255] +
255 - indexed[1]];
indexed += bpp;
gray ++;
width --;
}
}
1997-11-25 06:05:25 +08:00
}
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 */
lut_t *lut, /* I - Brightness lookup table */
unsigned char *cmap, /* I - Colormap */
vars_t *vars /* I - Saturation */
)
1997-11-25 06:05:25 +08:00
{
if (bpp == 1)
{
/*
* No alpha in image...
*/
while (width > 0)
{
rgb[0] = lut->red[cmap[*indexed * 3 + 0]];
rgb[1] = lut->green[cmap[*indexed * 3 + 1]];
rgb[2] = lut->blue[cmap[*indexed * 3 + 2]];
if (vars->saturation != 1.0)
{
2000-02-07 23:49:54 +08:00
double h, s, v;
unsigned char rgb1[3];
rgb1[0] = rgb[0];
rgb1[1] = rgb[1];
rgb1[2] = rgb[2];
gimp_rgb_to_hsv4 (rgb1, &h, &s, &v);
s = pow(s, 1.0 / vars->saturation);
2000-02-07 23:49:54 +08:00
gimp_hsv_to_rgb4 (rgb1, h, s, v);
rgb[0] = rgb1[0];
rgb[1] = rgb1[1];
rgb[2] = rgb1[2];
}
rgb += 3;
indexed ++;
width --;
}
}
else
1997-11-25 06:05:25 +08:00
{
/*
* RGBA image...
*/
while (width > 0)
{
rgb[0] = lut->red[cmap[indexed[0] * 3 + 0] * indexed[1] / 255 +
255 - indexed[1]];
rgb[1] = lut->green[cmap[indexed[0] * 3 + 1] * indexed[1] / 255 +
255 - indexed[1]];
rgb[2] = lut->blue[cmap[indexed[0] * 3 + 2] * indexed[1] / 255 +
255 - indexed[1]];
if (vars->saturation != 1.0)
{
2000-02-07 23:49:54 +08:00
double h, s, v;
unsigned char rgb1[3];
rgb1[0] = rgb[0];
rgb1[1] = rgb[1];
rgb1[2] = rgb[2];
gimp_rgb_to_hsv4 (rgb1, &h, &s, &v);
s = pow(s, 1.0 / vars->saturation);
2000-02-07 23:49:54 +08:00
gimp_hsv_to_rgb4 (rgb1, h, s, v);
rgb[0] = rgb1[0];
rgb[1] = rgb1[1];
rgb[2] = rgb1[2];
}
rgb += 3;
indexed += bpp;
width --;
}
}
1997-11-25 06:05:25 +08:00
}
1997-11-25 06:05:25 +08:00
/*
* 'rgb_to_gray()' - Convert RGB image data to grayscale.
*/
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 */
lut_t *lut, /* I - Brightness lookup table */
unsigned char *cmap, /* I - Colormap (unused) */
vars_t *vars /* I - Saturation */
)
1997-11-25 06:05:25 +08:00
{
if (bpp == 3)
1997-11-25 06:05:25 +08:00
{
/*
* No alpha in image...
*/
while (width > 0)
{
*gray = lut->composite[(rgb[0] * LUM_RED +
rgb[1] * LUM_GREEN +
rgb[2] * LUM_BLUE) / 100];
gray ++;
rgb += 3;
width --;
}
}
else
{
/*
* Image has alpha channel...
*/
while (width > 0)
{
*gray = lut->composite[((rgb[0] * LUM_RED +
rgb[1] * LUM_GREEN +
rgb[2] * LUM_BLUE) *
rgb[3] / 25500 + 255 - rgb[3])];
gray ++;
rgb += bpp;
width --;
}
}
1997-11-25 06:05:25 +08:00
}
/*
* 'rgb_to_rgb()' - Convert rgb image data to RGB.
1997-11-25 06:05:25 +08:00
*/
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 */
lut_t *lut, /* I - Brightness LUT */
unsigned char *cmap, /* I - Colormap */
vars_t *vars /* I - Saturation */
)
1997-11-25 06:05:25 +08:00
{
if (bpp == 3)
{
/*
* No alpha in image...
*/
while (width > 0)
{
rgbout[0] = lut->red[rgbin[0]];
rgbout[1] = lut->green[rgbin[1]];
rgbout[2] = lut->blue[rgbin[2]];
if (vars->saturation != 1.0 || vars->contrast != 100)
{
2000-02-07 23:49:54 +08:00
double h, s, v;
unsigned char rgb1[3];
rgb1[0] = rgbout[0];
rgb1[1] = rgbout[1];
rgb1[2] = rgbout[2];
gimp_rgb_to_hsv4 (rgb1, &h, &s, &v);
if (vars->saturation != 1.0)
s = pow(s, 1.0 / vars->saturation);
#if 0
if (vars->contrast != 100)
{
double contrast = vars->contrast / 100.0;
double tv = fabs(v - .5) * 2.0;
tv = pow(tv, 1.0 / (contrast * contrast));
if (v < .5)
tv = - tv;
v = (tv / 2.0) + .5;
}
#endif
2000-02-07 23:49:54 +08:00
gimp_hsv_to_rgb4 (rgb1, h, s, v);
rgbout[0] = rgb1[0];
rgbout[1] = rgb1[1];
rgbout[2] = rgb1[2];
}
if (vars->density != 1.0)
{
float t;
int i;
for (i = 0; i < 3; i++)
{
t = ((float) rgbout[i]) / 65536.0;
t = (1.0 + ((t - 1.0) * vars->density));
if (t < 0.0)
t = 0.0;
rgbout[i] = (unsigned short) (t * 65536.0);
}
}
rgbin += 3;
rgbout += 3;
width --;
}
}
else
1997-11-25 06:05:25 +08:00
{
/*
* RGBA image...
*/
1997-11-25 06:05:25 +08:00
while (width > 0)
{
rgbout[0] = lut->red[rgbin[0] * rgbin[3] / 255 + 255 - rgbin[3]];
rgbout[1] = lut->green[rgbin[1] * rgbin[3] / 255 + 255 - rgbin[3]];
rgbout[2] = lut->blue[rgbin[2] * rgbin[3] / 255 + 255 - rgbin[3]];
if (vars->saturation != 1.0 || vars->contrast != 100 ||
vars->density != 1.0)
{
2000-02-07 23:49:54 +08:00
double h, s, v;
unsigned char rgb1[3];
rgb1[0] = rgbout[0];
rgb1[1] = rgbout[1];
rgb1[2] = rgbout[2];
gimp_rgb_to_hsv4 (rgb1, &h, &s, &v);
if (vars->saturation != 1.0)
s = pow(s, 1.0 / vars->saturation);
#if 0
if (vars->contrast != 100)
{
double contrast = vars->contrast / 100.0;
double tv = fabs(v - .5) * 2.0;
tv = pow(tv, 1.0 / (contrast * contrast));
if (v < .5)
tv = - tv;
v = (tv / 2.0) + .5;
}
#endif
2000-02-07 23:49:54 +08:00
gimp_hsv_to_rgb4 (rgb1, h, s, v);
rgbout[0] = rgb1[0];
rgbout[1] = rgb1[1];
rgbout[2] = rgb1[2];
}
if (vars->density != 1.0)
{
float t;
int i;
for (i = 0; i < 3; i++)
{
t = ((float) rgbout[i]) / 65536.0;
t = (1.0 + ((t - 1.0) * vars->density));
if (t < 0.0)
t = 0.0;
rgbout[i] = (unsigned short) (t * 65536.0);
}
}
rgbin += bpp;
rgbout += 3;
width --;
}
}
1997-11-25 06:05:25 +08:00
}
/* #define PRINT_LUT */
void
compute_lut(lut_t *lut,
float print_gamma,
float app_gamma,
vars_t *v)
{
float brightness, /* Computed brightness */
screen_gamma, /* Screen gamma correction */
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...
*/
float red = 100.0 / v->red ;
float green = 100.0 / v->green;
float blue = 100.0 / v->blue;
float contrast;
contrast = v->contrast / 100.0;
if (red < 0.01)
red = 0.01;
if (green < 0.01)
green = 0.01;
if (blue < 0.01)
blue = 0.01;
if (v->linear)
{
screen_gamma = app_gamma / 1.7;
brightness = v->brightness / 100.0;
}
else
{
brightness = 100.0 / v->brightness;
screen_gamma = app_gamma * brightness / 1.7;
}
print_gamma = v->gamma / print_gamma;
for (i = 0; i < 256; i ++)
{
if (v->linear)
{
double adjusted_pixel;
pixel = adjusted_pixel = (float) i / 255.0;
if (brightness < 1.0)
adjusted_pixel = adjusted_pixel * brightness;
else if (brightness > 1.0)
adjusted_pixel = 1.0 - ((1.0 - adjusted_pixel) / brightness);
if (pixel < 0)
adjusted_pixel = 0;
else if (pixel > 1.0)
adjusted_pixel = 1.0;
adjusted_pixel = pow(adjusted_pixel,
print_gamma * screen_gamma * print_gamma);
adjusted_pixel *= 65535.0;
red_pixel = green_pixel = blue_pixel = adjusted_pixel;
lut->composite[i] = adjusted_pixel;
lut->red[i] = adjusted_pixel;
lut->green[i] = adjusted_pixel;
lut->blue[i] = adjusted_pixel;
}
else
{
float temp_pixel;
pixel = (float) i / 255.0;
/*
* First, correct contrast
*/
temp_pixel = fabs((pixel - .5) * 2.0);
temp_pixel = pow(temp_pixel, 1.0 / contrast);
if (pixel < .5)
temp_pixel = -temp_pixel;
pixel = (temp_pixel / 2.0) + .5;
/*
* Second, perform screen gamma correction
*/
pixel = 1.0 - pow(pixel, screen_gamma);
/*
* Third, fix up red, green, blue values
*
* I don't know how to do this correctly. I think that what I'll do
* is if the correction is less than 1 to multiply it by the
* correction; if it's greater than 1, hinge it around 64K.
* Doubtless we can do better. Oh well.
*/
if (pixel < 0.0)
pixel = 0.0;
else if (pixel > 1.0)
pixel = 1.0;
red_pixel = pow(pixel, 1.0 / (red * red));
green_pixel = pow(pixel, 1.0 / (green * green));
blue_pixel = pow(pixel, 1.0 / (blue * blue));
/*
* Finally, fix up print gamma and scale
*/
pixel = 256.0 * (256.0 - 256.0 *
pow(pixel, print_gamma));
red_pixel = 256.0 * (256.0 - 256.0 *
pow(red_pixel, print_gamma));
green_pixel = 256.0 * (256.0 - 256.0 *
pow(green_pixel, print_gamma));
blue_pixel = 256.0 * (256.0 - 256.0 *
pow(blue_pixel, print_gamma));
if (pixel <= 0.0)
2000-01-27 00:00:48 +08:00
lut->composite[i] = 0;
else if (pixel >= 65535.0)
2000-01-27 00:00:48 +08:00
lut->composite[i] = 65535;
else
2000-01-27 00:00:48 +08:00
lut->composite[i] = (unsigned)(pixel);
if (red_pixel <= 0.0)
2000-01-27 00:00:48 +08:00
lut->red[i] = 0;
else if (red_pixel >= 65535.0)
2000-01-27 00:00:48 +08:00
lut->red[i] = 65535;
else
2000-01-27 00:00:48 +08:00
lut->red[i] = (unsigned)(red_pixel);
if (green_pixel <= 0.0)
2000-01-27 00:00:48 +08:00
lut->green[i] = 0;
else if (green_pixel >= 65535.0)
2000-01-27 00:00:48 +08:00
lut->green[i] = 65535;
else
2000-01-27 00:00:48 +08:00
lut->green[i] = (unsigned)(green_pixel);
if (blue_pixel <= 0.0)
2000-01-27 00:00:48 +08:00
lut->blue[i] = 0;
else if (blue_pixel >= 65535.0)
2000-01-27 00:00:48 +08:00
lut->blue[i] = 65535;
else
2000-01-27 00:00:48 +08:00
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
}
1997-11-25 06:05:25 +08:00
/*
* 'default_media_size()' - Return the size of a default page size.
*/
void
default_media_size(int model, /* I - Printer model */
char *ppd_file, /* I - PPD file (not used) */
char *media_size, /* I - Media size */
int *width, /* O - Width in points */
int *length) /* O - Length in points */
{
if (strcmp(media_size, "Letter") == 0)
{
*width = 612;
*length = 792;
}
else if (strcmp(media_size, "Legal") == 0)
{
*width = 612;
*length = 1008;
}
else if (strcmp(media_size, "Tabloid") == 0)
{
*width = 792;
*length = 1214;
}
else if (strcmp(media_size, "12x18") == 0)
{
*width = 864;
*length = 1296;
}
else if (strcmp(media_size, "A4") == 0)
{
*width = 595;
*length = 842;
}
else if (strcmp(media_size, "A3") == 0)
{
*width = 842;
*length = 1191;
}
else
{
*width = 0;
*length = 0;
}
}
#ifdef LEFTOVER_8_BIT
/*
* Everything here and below goes away when this is tested on all printers.
*/
#define LEVEL_3 255
#define LEVEL_2 213
#define LEVEL_1 127
#define LEVEL_0 0
void
dither_black4(unsigned char *gray, /* I - Grayscale pixels */
int row, /* I - Current Y coordinate */
int src_width, /* I - Width of input row */
int dst_width, /* I - Width of output rows */
unsigned char *black) /* O - Black bitmap pixels */
{
int x, /* Current X coordinate */
xerror, /* X error count */
xstep, /* X step */
xmod, /* X error modulus */
length; /* Length of output bitmap in bytes */
unsigned char bit, /* Current bit */
*kptr; /* Current black pixel */
int k, /* Current black value */
ditherk, /* Next error value in buffer */
*kerror0, /* Pointer to current error row */
*kerror1; /* Pointer to next error row */
int ditherbit; /* Random dither bitmask */
xstep = src_width / dst_width;
xmod = src_width % dst_width;
length = (dst_width + 7) / 8;
kerror0 = error[row & 1][3];
kerror1 = error[1 - (row & 1)][3];
memset(black, 0, length * 2);
for (x = 0, bit = 128, kptr = black, xerror = 0, ditherbit = rand(),
ditherk = kerror0[0];
x < dst_width;
x ++, kerror0 ++, kerror1 ++)
{
k = 255 - *gray + ditherk / 8;
if (k > ((LEVEL_2 + LEVEL_3) / 2))
{
kptr[0] |= bit;
kptr[length] |= bit;
k -= LEVEL_3;
}
else if (k > ((LEVEL_1 + LEVEL_2) / 2))
{
kptr[length] |= bit;
k -= LEVEL_2;
}
else if (k > ((LEVEL_0 + LEVEL_1) / 2))
{
kptr[0] |= bit;
k -= LEVEL_1;
}
if (ditherbit & bit)
{
kerror1[0] = 5 * k;
ditherk = kerror0[1] + 3 * k;
}
else
{
kerror1[0] = 3 * k;
ditherk = kerror0[1] + 5 * k;
}
if (bit == 1)
{
kptr ++;
bit = 128;
ditherbit = rand();
}
else
bit >>= 1;
gray += xstep;
xerror += xmod;
if (xerror >= dst_width)
{
xerror -= dst_width;
gray ++;
}
}
}
void
dither_cmyk4(unsigned char *rgb, /* I - RGB pixels */
int row, /* I - Current Y coordinate */
int src_width, /* I - Width of input row */
int dst_width, /* I - Width of output rows */
unsigned char *cyan, /* O - Cyan bitmap pixels */
unsigned char *magenta, /* O - Magenta bitmap pixels */
unsigned char *yellow, /* O - Yellow bitmap pixels */
unsigned char *black) /* O - Black bitmap pixels */
{
int x, /* Current X coordinate */
xerror, /* X error count */
xstep, /* X step */
xmod, /* X error modulus */
length; /* Length of output bitmap in bytes */
int c, m, y, k, /* CMYK values */
divk, /* Inverse of K */
diff; /* Average color difference */
unsigned char bit, /* Current bit */
*cptr, /* Current cyan pixel */
*mptr, /* Current magenta pixel */
*yptr, /* Current yellow pixel */
*kptr; /* Current black pixel */
int ditherc, /* Next error value in buffer */
*cerror0, /* Pointer to current error row */
*cerror1; /* Pointer to next error row */
int dithery, /* Next error value in buffer */
*yerror0, /* Pointer to current error row */
*yerror1; /* Pointer to next error row */
int ditherm, /* Next error value in buffer */
*merror0, /* Pointer to current error row */
*merror1; /* Pointer to next error row */
int ditherk, /* Next error value in buffer */
*kerror0, /* Pointer to current error row */
*kerror1; /* Pointer to next error row */
int ditherbit; /* Random dither bitmask */
xstep = 3 * (src_width / dst_width);
xmod = src_width % dst_width;
length = (dst_width + 7) / 8;
cerror0 = error[row & 1][0];
cerror1 = error[1 - (row & 1)][0];
merror0 = error[row & 1][1];
merror1 = error[1 - (row & 1)][1];
yerror0 = error[row & 1][2];
yerror1 = error[1 - (row & 1)][2];
kerror0 = error[row & 1][3];
kerror1 = error[1 - (row & 1)][3];
memset(cyan, 0, length * 2);
memset(magenta, 0, length * 2);
memset(yellow, 0, length * 2);
memset(black, 0, length * 2);
for (x = 0, bit = 128, cptr = cyan, mptr = magenta, yptr = yellow,
kptr = black, xerror = 0, ditherbit = rand(), ditherc = cerror0[0],
ditherm = merror0[0], dithery = yerror0[0], ditherk = kerror0[0];
x < dst_width;
x ++, cerror0 ++, cerror1 ++, merror0 ++, merror1 ++, yerror0 ++,
yerror1 ++, kerror0 ++, kerror1 ++)
{
/*
* First compute the standard CMYK separation color values...
*/
c = 255 - rgb[0];
m = 255 - rgb[1];
y = 255 - rgb[2];
k = MIN(c, MIN(m, y));
/*
* Since we're printing black, adjust the black level based upon
* the amount of color in the pixel (colorful pixels get less black)...
*/
diff = 255 - (abs(c - m) + abs(c - y) + abs(m - y)) / 3;
diff = diff * diff * diff / 65025; /* diff = diff^3 */
k = diff * k / 255;
divk = 255 - k;
if (divk == 0)
c = m = y = 0; /* Grayscale */
else
{
/*
* Full color; update the CMY values for the black value and reduce
* CMY as necessary to give better blues, greens, and reds... :)
*/
c = (255 - rgb[1] / 4) * (c - k) / divk;
m = (255 - rgb[2] / 4) * (m - k) / divk;
y = (255 - rgb[0] / 4) * (y - k) / divk;
}
k += ditherk / 8;
if (k > ((LEVEL_2 + LEVEL_3) / 2))
{
kptr[0] |= bit;
kptr[length] |= bit;
k -= LEVEL_3;
}
else if (k > ((LEVEL_1 + LEVEL_2) / 2))
{
kptr[length] |= bit;
k -= LEVEL_2;
}
else if (k > ((LEVEL_0 + LEVEL_1) / 2))
{
kptr[0] |= bit;
k -= LEVEL_1;
}
if (ditherbit & bit)
{
kerror1[0] = 5 * k;
ditherk = kerror0[1] + 3 * k;
}
else
{
kerror1[0] = 3 * k;
ditherk = kerror0[1] + 5 * k;
}
c += ditherc / 8;
if (c > ((LEVEL_2 + LEVEL_3) / 2))
{
cptr[0] |= bit;
cptr[length] |= bit;
c -= LEVEL_3;
}
else if (c > ((LEVEL_1 + LEVEL_2) / 2))
{
cptr[length] |= bit;
c -= LEVEL_2;
}
else if (c > ((LEVEL_0 + LEVEL_1) / 2))
{
cptr[0] |= bit;
c -= LEVEL_1;
}
if (ditherbit & bit)
{
cerror1[0] = 5 * c;
ditherc = cerror0[1] + 3 * c;
}
else
{
cerror1[0] = 3 * c;
ditherc = cerror0[1] + 5 * c;
}
m += ditherm / 8;
if (m > ((LEVEL_2 + LEVEL_3) / 2))
{
mptr[0] |= bit;
mptr[length] |= bit;
m -= LEVEL_3;
}
else if (m > ((LEVEL_1 + LEVEL_2) / 2))
{
mptr[length] |= bit;
m -= LEVEL_2;
}
else if (m > ((LEVEL_0 + LEVEL_1) / 2))
{
mptr[0] |= bit;
m -= LEVEL_1;
}
if (ditherbit & bit)
{
merror1[0] = 5 * m;
ditherm = merror0[1] + 3 * m;
}
else
{
merror1[0] = 3 * m;
ditherm = merror0[1] + 5 * m;
}
y += dithery / 8;
if (y > ((LEVEL_2 + LEVEL_3) / 2))
{
yptr[0] |= bit;
yptr[length] |= bit;
y -= LEVEL_3;
}
else if (y > ((LEVEL_1 + LEVEL_2) / 2))
{
yptr[length] |= bit;
y -= LEVEL_2;
}
else if (y > ((LEVEL_0 + LEVEL_1) / 2))
{
yptr[0] |= bit;
y -= LEVEL_1;
}
if (ditherbit & bit)
{
yerror1[0] = 5 * y;
dithery = yerror0[1] + 3 * y;
}
else
{
yerror1[0] = 3 * y;
dithery = yerror0[1] + 5 * y;
}
if (bit == 1)
{
cptr ++;
mptr ++;
yptr ++;
kptr ++;
bit = 128;
ditherbit = rand();
}
else
bit >>= 1;
rgb += xstep;
xerror += xmod;
if (xerror >= dst_width)
{
xerror -= dst_width;
rgb += 3;
}
}
}
void
gray_to_gray(unsigned char *grayin, /* I - RGB pixels */
unsigned char *grayout, /* O - RGB pixels */
int width, /* I - Width of row */
int bpp, /* I - Bytes-per-pixel in grayin */
unsigned char *cmap, /* I - Colormap (unused) */
float saturation /* I - Saturation */
)
{
if (bpp == 1)
{
/*
* No alpha in image...
*/
while (width > 0)
{
*grayout = lut->composite[*grayin];
grayin ++;
grayout ++;
width --;
}
}
else
{
/*
* Handle alpha in image...
*/
while (width > 0)
{
*grayout = lut->composite[grayin[0] * grayin[1] / 255] + 255 - grayin[1];
grayin += bpp;
grayout ++;
width --;
}
}
}
void
indexed_to_gray(unsigned char *indexed, /* I - Indexed pixels */
unsigned char *gray, /* O - Grayscale pixels */
int width, /* I - Width of row */
int bpp, /* I - Bytes/pix in indexed */
unsigned char *cmap, /* I - Colormap */
float saturation /* I - Saturation */
)
{
int i; /* Looping var */
unsigned char gray_cmap[256]; /* Grayscale colormap */
for (i = 0; i < 256; i ++, cmap += 3)
gray_cmap[i] = (cmap[0] * LUM_RED +
cmap[1] * LUM_GREEN +
cmap[2] * LUM_BLUE) / 100;
if (bpp == 1)
{
/*
* No alpha in image...
*/
while (width > 0)
{
*gray = lut->composite[gray_cmap[*indexed]];
indexed ++;
gray ++;
width --;
}
}
else
{
/*
* Handle alpha in image...
*/
while (width > 0)
{
*gray = lut->composite[gray_cmap[indexed[0] * indexed[1] / 255] +
255 - indexed[1]];
indexed += bpp;
gray ++;
width --;
}
}
}
#endif
1997-11-25 06:05:25 +08:00
/*
* End of "$Id$".
*/