Skip to content

Commit

Permalink
Simplify dithering code.
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelrsweet committed Nov 15, 2023
1 parent c097c8d commit 067ffe8
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 79 deletions.
72 changes: 18 additions & 54 deletions lprint-common.c
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ lprintDitherAlloc(
}

// Allocate memory...
if ((dither->input[0] = calloc(4 * dither->in_width, sizeof(lprint_pixel_t))) == NULL)
if ((dither->input[0] = calloc(4 * dither->in_width, sizeof(unsigned char))) == NULL)
{
papplLogJob(job, PAPPL_LOGLEVEL_ERROR, "Unable to allocate input buffer.");
return (false);
Expand Down Expand Up @@ -169,7 +169,7 @@ lprintDitherLine(
{
unsigned x, // Current column
count; // Remaining count
lprint_pixel_t *current, // Current line
unsigned char *current, // Current line
*prev, // Previous line
*next; // Next line
unsigned char *dline, // Dither line
Expand All @@ -182,7 +182,7 @@ lprintDitherLine(
count = dither->in_width;
next = dither->input[y & 3];

memset(next, 0, count * sizeof(lprint_pixel_t));
memset(next, 0, count);

if (line)
{
Expand All @@ -193,7 +193,7 @@ lprintDitherLine(
{
// Convert to 8-bit black...
if (byte & bit)
next->value = 255;
*next = 255;

if (bit > 1)
{
Expand All @@ -214,12 +214,11 @@ lprintDitherLine(
for (line += dither->in_left; count > 0; count --, next ++, line ++)
{
if (*line < LPRINT_WHITE)
next->value = 255;
*next = 255;
else if (*line > LPRINT_BLACK)
next->value = 0;
*next = 0;
else
next->value = 255 - *line;

*next = 255 - *line;
}
}
else
Expand All @@ -228,41 +227,18 @@ lprintDitherLine(
for (line += dither->in_left; count > 0; count --, next ++, line ++)
{
if (*line < LPRINT_WHITE)
next->value = 255;
*next = 255;
else if (*line > LPRINT_BLACK)
next->value = 0;
*next = 0;
else
next->value = *line;
*next = *line;
}
}
break;

default : // Something else...
return (false);
}

// Then look for runs of repeated pixels
for (count = dither->in_width, prev = dither->input[(y - 2) & 3], current = dither->input[(y - 1) & 3], next = dither->input[y & 3]; count > 0; count --, prev ++, current ++, next ++)
{
// Update repetition flags...
if (count > 1 && current[0].value == current[1].value)
{
current[0].repeat |= LPRINT_REPEAT_H;
current[1].repeat |= LPRINT_REPEAT_H;
}

if (prev->value == current->value)
{
prev->repeat |= LPRINT_REPEAT_V;
current->repeat |= LPRINT_REPEAT_V;
}

if (current->value == next->value)
{
current->repeat |= LPRINT_REPEAT_V;
next->repeat |= LPRINT_REPEAT_V;
}
}
}

// If we are outside the imageable area then don't dither...
Expand All @@ -272,38 +248,26 @@ lprintDitherLine(
// Dither...
for (x = 0, count = dither->in_width, prev = dither->input[(y - 2) & 3], current = dither->input[(y - 1) & 3], next = dither->input[y & 3], outptr = dither->output, byte = dither->out_white, bit = 128, dline = dither->dither[y & 15]; count > 0; x ++, count --, prev ++, current ++, next ++)
{
if (current->value)
if (*current)
{
// Not pure white/blank...
if (current->value == 255)
if (*current == 255)
{
// 100% black...
byte ^= bit;
}
else
{
// Something potentially to threshold:
//
// - this pixel borders a 100% black run
// - this pixel is a 1 dot wide line between whitespace
// - this pixel is a 1 dot wide line between other 1 dot
// wide lines (striped)
//
// Otherwise use dithering...
if ((!(current->repeat & LPRINT_REPEAT_H) && x > 0 && current[-1].value == 255 && current[-1].repeat) ||
(!(current->repeat & LPRINT_REPEAT_H) && count > 1 && current[1].value == 255 && current[1].repeat) ||
(prev->value == 255 && prev->repeat) ||
(next->value == 255 && next->repeat) ||
(!(current->repeat & LPRINT_REPEAT_H) && (x == 0 || !current[-1].value) && (count == 1 || !current[1].value)) ||
((current->repeat & LPRINT_REPEAT_H) && !prev->value && prev->repeat && !next->value && next->repeat) ||
(current->repeat == LPRINT_REPEAT_V && (x == 0 || current[-1].repeat == LPRINT_REPEAT_V || current[-1].value == 255) && (count == 1 || current[1].repeat == LPRINT_REPEAT_V || current[1].value == 255)) ||
(current->repeat == LPRINT_REPEAT_H && (prev->repeat == LPRINT_REPEAT_H || prev->value == 255) && (next->repeat == LPRINT_REPEAT_V || next->value == 255)))
// Only dither if this pixel does not border 100% white or black...
if ((x > 0 && (current[-1] == 255 || current[-1] == 0)) ||
(count > 1 && (current[1] == 255 || current[1] == 0)) ||
*prev == 255 || *prev == 0 || *next == 255 || *next == 0)
{
// Threshold
if (current->value > 127)
if (*current > 127)
byte ^= bit;
}
else if (current->value > dline[x & 15])
else if (*current > dline[x & 15])
{
// Dither anything else
byte ^= bit;
Expand Down
49 changes: 24 additions & 25 deletions lprint.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,43 +55,48 @@
# define cups_len_t int
# define cups_page_header_t cups_page_header2_t
# define cupsArrayNew cupsArrayNew3
# define cupsArrayGetCount cupsArrayCount
# define cupsArrayGetElement(a,n) cupsArrayIndex(a,(int)n)
# define cupsArrayGetFirst cupsArrayFirst
# define cupsArrayGetLast cupsArrayLast
# define cupsArrayGetNext cupsArrayNext
# define cupsArrayGetPrev cupsArrayPrev
# define cupsGetUser cupsUser
# define cupsLangGetName(lang) lang->language
# define cupsRasterReadHeader cupsRasterReadHeader2
# define cupsRasterWriteHeader cupsRasterWriteHeader2
# define cupsTempFd(prefix,suffix,buffer,bufsize) cupsTempFd(buffer,bufsize)
# define httpAddrConnect httpAddrConnect2
# define httpAddrGetFamily httpAddrFamily
# define httpAddrGetLength httpAddrLength
# define httpAddrGetString httpAddrString
# define httpAddrIsLocalhost httpAddrLocalhost
# define httpConnect httpConnect2
# define httpDecode64(out,outlen,in,end) httpDecode64_2(out,outlen,in)
# define httpEncode64(out,outlen,in,inlen,url) httpEncode64_2(out,outlen,in,inlen)
# define httpGetDateString httpGetDateString2
# define httpRead httpRead2
# define httpReconnect httpReconnect2
# define httpSetEncryption(http,e) (httpEncryption(http,e)>=0)
# define httpStatusString httpStatus
# define httpWrite httpWrite2
# define httpWriteResponse(http,code) (httpWriteResponse(http,code) == 0)
# define ippGetFirstAttribute ippFirstAttribute
# define ippGetNextAttribute ippNextAttribute
# define IPP_NUM_CAST (int)
# if CUPS_VERSION_MINOR < 3
# define HTTP_STATUS_FOUND (http_status_t)302
# endif // CUPS_VERSION_MINOR < 3
# if CUPS_VERSION_MINOR < 5
# define cupsArrayGetCount cupsArrayCount
# define cupsArrayGetElement(a,n) cupsArrayIndex(a,(int)n)
# define cupsArrayGetFirst cupsArrayFirst
# define cupsArrayGetLast cupsArrayLast
# define cupsArrayGetNext cupsArrayNext
# define cupsArrayGetPrev cupsArrayPrev
# define cupsGetUser cupsUser
# define httpAddrConnect httpAddrConnect2
# define httpAddrGetFamily httpAddrFamily
# define httpAddrGetLength httpAddrLength
# define httpAddrGetString httpAddrString
# define httpAddrIsLocalhost httpAddrLocalhost
# define httpSetEncryption(http,e) (httpEncryption(http,e)>=0)
# define ippGetFirstAttribute ippFirstAttribute
# define ippGetNextAttribute ippNextAttribute
typedef cups_array_func_t cups_array_cb_t;
typedef cups_acopy_func_t cups_acopy_cb_t;
typedef cups_afree_func_t cups_afree_cb_t;
typedef cups_raster_iocb_t cups_raster_cb_t;
typedef ipp_copycb_t ipp_copy_cb_t;
# if CUPS_VERSION_MINOR < 3
# define HTTP_STATUS_FOUND (http_status_t)302
# endif // CUPS_VERSION_MINOR < 3
# else
# define httpDecode64 httpDecode64_3
# define httpEncode64 httpEncode64_3
# endif // CUPS_VERSION_MINOR < 5
# else
# define cups_len_t size_t
# define cups_utf8_t char
Expand Down Expand Up @@ -121,16 +126,10 @@ enum
LPRINT_REPEAT_ALL = 0x03
};

typedef struct lprint_pixel_s // Pixel for dithering
{
unsigned char repeat, // Repetition flags
value; // Value
} lprint_pixel_t;

typedef struct lprint_dither_s // Dithering state
{
pappl_dither_t dither; // Dither matrix to use
lprint_pixel_t *input[4]; // Input lines for dithering (only 3 are needed, 4 makes it easier for ring buffer)
unsigned char *input[4]; // Input lines for dithering (only 3 are needed, 4 makes it easier for ring buffer)
unsigned in_width, // Width in pixels
in_height, // Height in lines
in_left, // Left (starting) pixel
Expand Down

0 comments on commit 067ffe8

Please sign in to comment.