/***************************************************************************
image.c - code for reading and parsing a pbm, pgm or ppm format file
also, rgb -> cymk conversion and black separation
-------------------
begin : Thu Jan 13 2000
copyright : (C) 2000 by pnm2ppa project
email :
***************************************************************************/
/***************************************************************************
* *
* 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. *
* *
***************************************************************************/
#include <stdlib.h>
#include <string.h>
#include <math.h>
#define __IMAGE_C__
#include "syslog.h"
#include "global.h"
#include "defaults.h"
#include "debug.h"
#include "image.h"
#include "gamma.h"
#include "dither.h"
#include "lang.h"
int
initImage (image_t *image, FILE *fptr)
{
char line[1024];
int colors = 0;
int k, k1;
image->fptr = fptr;
image->version = none;
image->blackCurLine = 0;
image->colorCurLine = 0;
image->bufferCurLine = 0;
image->unread = 0;
image->colors = 0;
if (gGammaMode)
{
/* produce color calibration page, uses the default papersize */
image->version = P6_PPMRAW;
image->width = gWidth;
image->height = gHeight;
}
else
{
if (fgets (line, 1024, fptr) == NULL)
return 0;
line[strlen (line) - 1] = 0;
/* we have to handle the six pnm formats .
*/
if (!strcmp (line, "P1"))
{
image->version = P1_PBM;
if (!gPixmapMode)
gColorMode = false ;
strcpy(gFormat,"BitMap");
}
if (!strcmp (line, "P2"))
{
image->version = P2_PGM;
if (!gPixmapMode)
gColorMode = false ;
strcpy(gFormat,"GreyMap");
}
if (!strcmp (line, "P3"))
{
image->version = P3_PPM;
strcpy(gFormat,"PixMap");
}
if (!strcmp (line, "P4"))
{
image->version = P4_PBMRAW;
if (!gPixmapMode)
gColorMode = false ;
strcpy(gFormat,"BitMap");
}
if (!strcmp (line, "P5"))
{
image->version = P5_PGMRAW;
if (!gPixmapMode)
gColorMode = false ;
strcpy(gFormat,"GreyMap");
}
if (!strcmp (line, "P6"))
{
image->version = P6_PPMRAW;
strcpy(gFormat,"PixMap");
}
if (image->version == none)
{
snprintf(syslog_message,message_size,"initImage(): %s",
gMessages[E_IM_BADFORMAT] );
wrap_syslog (LOG_CRIT,"%s",syslog_message);
return 0;
}
/* initialize switch that is used to terminate further printing
* if EOF is detected while reading the input image
*/
gTerminate = false ;
do
if (fgets (line, 1024, fptr) == NULL)
return 0;
while (line[0] == '#');
if (2 != sscanf (line, "%d %d", &image->width, &image->height))
return 0;
/* use the image dimensions read from the pnm innput file to
* set gWidth and gHeight, and test that these are accepatable
* for the printer model
* this will mean that any user input or default papersizes
* will only be uses for calibration or gamma correction output
* which is not generated by pnm imput
*/
gWidth = image->width ;
gHeight = image->height ;
/* test that papersize is acceptable */
if ( (gWidth > gmaxWidth )
|| (gWidth < gminWidth )
|| (gHeight > gmaxHeight )
|| (gHeight < gminHeight )
)
{
snprintf(syslog_message,message_size,"initImage(): %s %dx%d @600dpi\n",
gMessages[E_IM_BADPAPERSIZE], gWidth, gHeight);
wrap_syslog (LOG_CRIT,"%s",syslog_message);
return 0;
}
switch(image->version)
{
case P2_PGM:
case P3_PPM:
case P5_PGMRAW:
case P6_PPMRAW:
if (fgets (line, 1024, fptr) == NULL)
return 0;
if (1 != sscanf (line, "%d", &colors))
return 0;
/* colors should be 255, as the code is currently implemented */
if (colors != 255)
{
snprintf(syslog_message,message_size,"initImage(): %s %d\n",
gMessages[E_IM_BADMAXVALUE], colors);
wrap_syslog (LOG_CRIT,"%s",syslog_message);
return 0;
}
break;
case P1_PBM:
case P4_PBMRAW:
colors = 1;
break;
case none:
default:
snprintf(syslog_message,message_size,"initImage(): %s",
gMessages[E_IM_BADFORMAT]);
wrap_syslog (LOG_CRIT,"%s",syslog_message);
return 0;
break;
}
image->colors = colors ;
DPRINTF( "initImage: width=%d, height=%d, colors = %d\n",
image->width, image->height, image->colors);
}
/* initialize buffer */
image->bufsize = 8192;
image->bufpos = 0;
image->buflines = 0;
image->buftype = empty;
for (k = 0; k < gMaxPass; k++)
{
image->buffer[k] = malloc (image->bufsize);
if (!image->buffer[k])
{
for (k1 = 0; k1 < k; k1++)
free (image->buffer[k1]);
return 0;
}
}
return 1;
}
int
remallocBuffer (image_t *image, size_t bytes)
{
int linesize;
unsigned char *newbuf;
// size_t newsize;
int newsize ;
int k;
if (image->buftype == bitmap)
linesize = (image->width + 7) / 8;
else if (image->buftype == color)
linesize = (image->width / 2 + 7) / 8 * 3;
else
linesize = 0;
/* if space is adequate, do nothing */
if (image->bufpos + image->buflines * linesize + bytes < image->bufsize)
return 0;
/* if there's an offset, move the image at buffer[k][bufpos] to the
* the beginning of the buffer, and reset the offset to 0.
*/
if (image->bufpos != 0)
{
DPRINTF("Moving image[k][bufpos] to image[k][0]\n");
for (k = 0; k < gMaxPass; k++)
memmove (image->buffer[k],
&image->buffer[k][image->bufpos], image->buflines * linesize);
image->bufpos = 0;
if (image->bufpos + image->buflines * linesize + bytes < image->bufsize)
return 0;
}
// calculate the number of bits and add one to double the needed memory
// size.
newsize = pow(2, (int)((log(image->buflines * linesize + bytes)/log(2))+1));
DPRINTF("resizing memory from %d bytes to %d bytes\n",
image->bufsize, newsize);
for (k=0; k < gMaxPass; k++)
{
newbuf = malloc(newsize);
if ( ! newbuf )
{
snprintf(syslog_message,message_size, "remallocBuffer(): %s",
gMessages[E_BADMALLOC]);
wrap_syslog (LOG_CRIT,"%s",syslog_message);
exit (1);
}
memcpy(newbuf, image->buffer[k], image->buflines * linesize);
free(image->buffer[k]);
image->buffer[k] = newbuf;
}
image->bufsize = newsize;
return 0;
}
void
convert_black_data (image_t *image, unsigned char *line, unsigned char *black)
{
/* Lets document this - please correct anything incorrect here!
(duncan, Feb 12 2000, updated July 2000)
- The entries in line[] are written by one of the
functions FS_Color_Dither(), HT_Color_Dither(), HT_Black_Dither()
in dither.c
- The entries in line[] represent the ( image->width ) pixels on a line.
Each pixel is represented by three consecutive entries
(line[i] , line [i + 1] ,line [i + 2] ) ,
where i = 0, 3, 6 , ... , < (image->width * 3)
The three entries correspond to Cyan, Magenta, and Yellow ink.
- entries in line[] take values 1, 2,...,(gMaxPass + 1) , 0 or 255,
where gMaxPass is the maximum number of passes of the color print head.
* gMaxPass is only used in Color mode (gColorMode=true)
* In normal color mode (gEcomode=false, gFastmode=false) gMaxPass = 4
* In Economy mode (gEcoMode = true) gMaxPass = 1
* In Fast Color mode (gFastMode = true) gMaxPass = 1
- values line [] = 1, 2, ..., gMaxPass correspond to
gMaxPass, gMaxPass-1, ..., 1 drops of ink of a given color (C, M,or Y).
- the value line [] = 0 also means gMaxPass drops of ink
- the value line [] > gMaxPass (usually = gMaxPass+1 or 255)
means 0 drops of color ink.
- an entry (0, 0, 0) corresponds to a black drop, which can
either be a drop of black ink, or gMaxPass drops each of C,M and Y ink,
If this is implemented with a drop of black ink, convert_black_data()
changes (0,0,0) to (255,255,255), so it won't get repeated using
colored ink by the following call to convert_color_data().
- whitespace is coded by (255,255,255).
Color data is only printed on even lines.
Black data is printed on even and odd lines,
except in Black-and-White Economy mode (gColorMode=false,
gEcoMode=true), when only even lines of black are printed.
If the odd line is not printed, its black data is added to
the next even line.
*/
int i, j, k;
unsigned char mask = 0x80;
unsigned char *pos = black;
int blackness ;
unsigned char curr_stuff= 0 ; // 0 = white, 1 = not white (current pixel)
unsigned char remove_black = 1, have_color = 0;
unsigned char first_black=0 , second_black=0 ; //controls black ink density
blackness = gBlackness ;
j = image->bufferCurLine ;
/* black ink quantity control (duncan) */
/* this should be extended to control color ink printing
of "black" pixels */
if ( blackness == 1 )
{
/* one black ink drop, on even lines only */
if ( (j % 2) )
{
first_black = 0 ; /* odd lines */
second_black = 0;
}
else
{
first_black = 0 ; /* even lines */
second_black = 1 ;
}
}
else if ( blackness == 2 )
/* two black ink drops */
{
if ( (j % 2) )
{
first_black = 1 ; /* odd lines */
second_black = 0;
}
else
{
// first_black = 0 ; /* even lines */
// second_black = 1 ;
/* treat odd and even lines the same, to avoid artifacts?*/
first_black = 1 ; /* even lines */
second_black = 0 ;
}
}
else if ( blackness == 3 )
/* two drops on even lines, one on odd lines */
{
first_black = 1;
if ( j % 2 )
second_black = 0; /* odd lines */
else
second_black = 1 ; /* even lines */
}
else if (blackness == 4 )
/* two black ink drops, all lines */
{
first_black = 1 ;
second_black = 1 ;
}
else
/* no black ink */
{
first_black = 0 ;
second_black = 0 ;
}
/* In Pixmap mode black ink cartridge is disabled (this should
be renamed to (say) NoBlack mode ) */
if (gPixmapMode)
memset (pos, 0x00, (image->width + 7) / 8);
else
{
if (gColorMode)
{
/* This is the most delicate situation, we (may) have both color
* and black on the same line;
* we want to:
* - Print half of the black ink to avoid "wet" effect
* - get a good "covering" black in pixmaps (neither too dense,
* neither too sparse...)
*/
curr_stuff=0;
for (i = 0; i < image->width * 3; i += 6)
{
if (mask == 0x80)
*pos = 0;
if (curr_stuff==0)
{
/* this is a test to see if the current non-whitespace
* pixel is part of a region of black delineated by
* whitespace (have_color=0)
* or is in a region containing some
* colored pixels (in this case have_color=1)
*/
if (! (line[i]>gMaxPass && //if line is not white
line[i+1]> gMaxPass &&
line[i+2]>gMaxPass) )
{
have_color=0;
k=i;
while ( (!(have_color)) &&
(k<image->width * 3) &&
(! (line[k]>gMaxPass &&
line[k+1]> gMaxPass &&
line[k+2]>gMaxPass) ))
{
if ((line[k] && line[k]<=gMaxPass) ||
(line[k+1] && line[k+1]<=gMaxPass) ||
(line[k+2] && line[k+2]<=gMaxPass))
have_color=1;
k+=6;
}
if (have_color)
remove_black=0;
else
remove_black=1;
curr_stuff=1;
}
}
if ( !(line[i] || line[i + 1] || line[i + 2]))
{
/* pixel is black; there are two possible
* behaviors, depending on whether remove_black
* is set by Drugo's new code above.
* these behaviors may need some further
* adjustments.
*/
if (remove_black)
{
/* in this case the black region is
* identified as delineated by whitespace
* (probably = text?).
* So print with black ink,
* and no colored ink. To avoid using
* too much black ink (wets paper)
* first_black and second_black
* are used as controls on amount
* of black ink.
*/
if (first_black && gBlack )
*pos |= mask; /* one drop of black ink */
mask >>= 1;
if (mask == 0)
{
pos++;
mask = 0x80;
}
if (second_black && gBlack )
*pos |= mask; /* one drop of black ink */
/* suppress use of colored ink on this pixel */
line[i] = line[i + 1] = line[i + 2] = 255;
line[i + 3] = line[i + 4] = line[i + 5] = 255;
}
else
{
/* this black region is bounded by a colored
* region, and is probably part of an image.
* so: print half strength black ink, and use
* some colored ink.
*
* note: in EcoMode, only even lines are processed.
* in normal mode, skip even lines.
* j is the line number.
*/
if ( (j % 2 || gEcoMode ) && gBlack )
*pos |= mask;/* a drop of black, every second line */
mask >>= 1;
if (mask == 0)
{
pos++;
mask = 0x80;
}
/* reduce amount of colored ink to avoid wetting:
* try resetting line[] to gMaxPass-1
* gives 2 passes of the color head in high quality,
* (gMaxPass=4, line[] = 3),
* 1 pass in ecoMode (gMaxPass = 1, line[] = 0)
*/
line[i] = line[i + 1] = line[i + 2] = gMaxPass-1;
line[i + 3] = line[i + 4] = line[i + 5] = gMaxPass-1;
}
}
else
{
/* pixel is not black */
mask >>= 1;
if (mask == 0)
{
pos++;
mask = 0x80;
}
if (line[i] > gMaxPass &&
line[i + 1] > gMaxPass &&
line[i + 2] > gMaxPass)
{
/* pixel is whitespace */
curr_stuff=0;
}
}
mask >>= 1;
if (mask == 0)
{
pos++;
mask = 0x80;
}
}
}
else
{
/* this next part is for printing in black and white only.
* if !gColorMode, the line contains only black or white, so
* we can print safely 1 drop out of 2 without any problem
*/
*pos = 0;
for (i = 0 ; i < image->width * 3; i += 6)
{
if (mask == 0x80)
*pos = 0;
if ((!line[i] && !line[i + 1] && !line[i + 2]))
{
if (first_black && gBlack)
*pos |= mask; /* one drop of black ink */
mask >>= 1;
if (mask == 0)
{
pos++;
mask = 0x80;
}
if (second_black && gBlack)
*pos |= mask; /* one drop of black ink */
}
else
{
/* pixel is not black */
mask >>= 1;
if (mask == 0)
{
pos++;
mask = 0x80;
}
}
mask >>= 1;
if (mask == 0)
{
pos++;
mask = 0x80;
}
}
memset (line, 0xff, image->width * 3);
}
}
}
void
convert_color_data (image_t *image, unsigned char *line,
unsigned char *color[], int c_off)
{
int i, k, j;
unsigned char mask;
unsigned char *pos;
j = 1;
for (k = 0; k < gMaxPass; k++)
{
mask = 0x80;
pos = &color[gMaxPass - j][c_off];
j++;
memset (pos, 0x00, (image->width / 2 + 7) / 8 * 3);
for (i = 0; i < image->width * 3; i += 6)
{
if ((line[i] < gMaxPass - (k) + 1) && gCyan)
pos[0] |= mask;
if ((line[i + 1] < gMaxPass - (k) + 1) && gMagenta)
pos[1] |= mask;
if ((line[i + 2] < gMaxPass - (k) + 1) && gYellow)
pos[2] |= mask;
mask >>= 1;
if (mask == 0)
{
pos += 3;
mask = 0x80;
}
}
}
}
/* Drugo */
/* read a line of data from the file and convert to the necessary format */
void
read_line (image_t * image, unsigned char *black[], int b_off,
unsigned char *color[], int c_off)
{
static unsigned char *line, *oldline; /* take care to free these! */
int i, j, k ;
int fread_eof = 0;
static int have_oldline = 0;
line = malloc (image->width * 3);
if (!line)
{
/* make this nicer... propagate upwards */
snprintf(syslog_message,message_size, "read_line(): %s",
gMessages[E_BADMALLOC]);
wrap_syslog (LOG_CRIT,"%s",syslog_message);
if (have_oldline)
free (oldline);
exit (1);
}
/* All the six pnm input formats
* (pbm, pbmraw, pgm, pgmraw, pbm, pbmraw )
* can be read from the input, and converted to
* ppmraw format for further processing.
*/
if (!gGammaMode && !gTerminate)
{
switch (image->version)
{
/* for completeness, the non-raw pnm formats are supported */
case P1_PBM:
for ( i = 0 ; i < image->width * 3 ; )
switch( getc( image->fptr ) )
{
case EOF:
snprintf(syslog_message,message_size, "read_line(): %s PBM\n",
gMessages[E_IM_EOFREADLINE]);
wrap_syslog (LOG_CRIT,"%s",syslog_message);
/* input data is truncated; set gTerminate mode
* and replace lost part of image with whitespace
* until print run ends.
*/
gTerminate = true ;
break;
case '1':
line[i] = line[i + 1]= line[i + 2] = 0;
i += 3 ;
break;
case '0':
line[i] = line[i + 1]= line[i + 2] = 255;
i += 3 ;
break;
default :
break;
}
break;
case P2_PGM:
{
/* This is included for completeness,
* but this implementation s PAINFULLY slow !
* is there a better way?
* (YES, USE THE PGMRAW FORMAT ONLY !)
*/
unsigned int value ;
for ( i = 0 ; i < image->width * 3 ; i += 3 )
{
switch (fscanf(image->fptr, "%u ", &value ) )
{
case '1':
break ;
case EOF:
snprintf(syslog_message,message_size,"read_line(): %s PGM\n",
gMessages[E_IM_EOFREADLINE]);
wrap_syslog (LOG_CRIT,"%s",syslog_message);
/* input data is truncated; set gTerminate mode
* and replace lost part of image with whitespace
* until print run ends.
*/
gTerminate = true ;
break;
default:
snprintf(syslog_message,message_size,"read_line(): %s",
gMessages[E_IM_BADREADLINE]);
wrap_syslog (LOG_CRIT,"%s",syslog_message);
free (line);
if (have_oldline)
free (oldline);
exit (1);
break;
}
if(value <= 255)
line[i] = line[i + 1] = line[i + 2] = value ;
else
{
snprintf(syslog_message,message_size,"read_line(): %s",
gMessages[E_IM_BADIMAGE]);
wrap_syslog (LOG_CRIT,"%s",syslog_message);
free (line);
if (have_oldline)
free (oldline);
exit (1);
}
}
}
break;
case P3_PPM:
{
/* This is included for completeness,
* but this implementation is PAINFULLY slow !
* is there a better way?
* (YES, USE THE PPMRAW FORMAT ONLY !)
*/
unsigned int value ;
for ( i = 0 ; i < image->width * 3 ; i ++ )
{
switch (fscanf(image->fptr, "%u ", &value ) )
{
case '1':
break ;
case EOF:
snprintf(syslog_message,message_size,"read_line(): %s PPM\n",
gMessages[E_IM_EOFREADLINE]);
wrap_syslog (LOG_CRIT,"%s",syslog_message);
/* input data is truncated; set gTerminate mode
* and replace lost part of image with whitespace
* until print run ends.
*/
gTerminate = true ;
break;
default:
snprintf(syslog_message,message_size,"read_line(): %s",
gMessages[E_IM_BADREADLINE]);
wrap_syslog (LOG_CRIT,"%s",syslog_message);
free (line);
if (have_oldline)
free (oldline);
exit (1);
break;
}
if(value <= 255)
line[i] = value ;
else
{
snprintf(syslog_message,message_size,"read_line() %s",
gMessages[E_IM_BADIMAGE]);
wrap_syslog (LOG_CRIT,"%s",syslog_message);
free (line);
if (have_oldline)
free (oldline);
exit (1);
}
}
}
break;
case P4_PBMRAW:
/* read pbmraw format and convert to ppmraw format */
{
int pbm_width, count, index ;
char* pbmraw_data;
unsigned char mask[8] =
{ 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };
pbm_width = ( image->width + 7 ) / 8;
if (! (pbmraw_data = malloc(pbm_width)) )
{
snprintf(syslog_message,message_size,"read_line(): %s",
gMessages[E_BADMALLOC]);
wrap_syslog (LOG_CRIT,"%s",syslog_message);
if (have_oldline)
free (oldline);
free (line);
exit (1);
}
count = fread(pbmraw_data, 1 , pbm_width, image->fptr);
if (pbm_width == count)
{
/* success */
/* pbm raw format: 0=white, 1=black;
* bits are stored eight per byte, high bit
* first, low bit last.
*/
index = 0;
for ( i = 0 ; i < image->width ; i ++ )
{
k = i % 8 ;
j = i / 8 ;
if ( pbmraw_data[j] & mask[k] )
line[index] = line[index + 1] = line[index + 2] = 0 ;
else
line[index] = line[index + 1] = line[index + 2] = 255; ;
index += 3;
}
free(pbmraw_data);
}
else
{
/* error reading line */
free(pbmraw_data);
fread_eof=feof(image->fptr);
clearerr(image->fptr);
if (fread_eof)
{
snprintf(syslog_message,message_size,"read_line(): %s PBMRAW\n",
gMessages[E_IM_EOFREADLINE]);
wrap_syslog (LOG_CRIT,"%s",syslog_message);
/* input data is truncated; set gTerminate mode
* and replace lost part of image with whitespace
* until print run ends.
*/
gTerminate = true ;
}
else
{
snprintf(syslog_message,message_size,"read_line(): %s",
gMessages[E_IM_BADREADLINE]);
wrap_syslog (LOG_CRIT,"%s",syslog_message);
free (line);
if (have_oldline)
free (oldline);
exit (1);
}
}
}
break;
case P5_PGMRAW:
/* read pgmraw format and convert to ppmraw format */
{
int index ;
char* pgm_data;
pgm_data = malloc(image->width);
if (!pgm_data)
{
snprintf(syslog_message,message_size,"read_line(): %s",
gMessages[E_BADMALLOC]);
wrap_syslog (LOG_CRIT,"%s",syslog_message);
free (line);
if (have_oldline)
free (oldline);
exit (1);
}
if ( 1 == fread (pgm_data, image->width , 1, image->fptr) )
{
/* success */
index = 0 ;
for ( i = 0 ; i < image->width ; i ++ )
{
line[index] = line[index + 1] = line[index + 2]
= pgm_data[i] ;
index += 3;
}
free(pgm_data);
}
else
{
/* error reading line */
free(pgm_data);
fread_eof=feof(image->fptr);
clearerr(image->fptr);
if (fread_eof)
{
snprintf(syslog_message,message_size,"read_line:() %s PGMRAW\n",
gMessages[E_IM_EOFREADLINE]);
wrap_syslog (LOG_CRIT,"%s",syslog_message);
/* input data is truncated; set gTerminate mode
* and replace lost part of image with whitespace
* until print run ends.
*/
gTerminate = true ;
}
else
{
snprintf(syslog_message,message_size,"read_line(): %s",
gMessages[E_IM_BADREADLINE]);
wrap_syslog (LOG_CRIT,"%s",syslog_message);
free (line);
if (have_oldline)
free (oldline);
exit (1);
}
}
}
break;
case P6_PPMRAW:
if (1 != fread (line, image->width * 3, 1, image->fptr) )
{
fread_eof=feof(image->fptr);
clearerr(image->fptr);
if (fread_eof)
{
snprintf(syslog_message,message_size,"read_line(): %s PPMRAW\n",
gMessages[E_IM_EOFREADLINE]);
wrap_syslog (LOG_CRIT,"%s",syslog_message);
/* input data is truncated; set gTerminate mode
* and replace lost part of image with whitespace
* until print run ends.
*/
gTerminate = true ;
}
else
{
snprintf(syslog_message,message_size,"read_line(): %s",
gMessages[E_IM_BADREADLINE]);
wrap_syslog (LOG_CRIT,"%s",syslog_message);
free (line);
if (have_oldline)
free (oldline);
exit (1);
}
}
break;
case none:
default:
snprintf(syslog_message,message_size,"read_line(): %s",
gMessages[E_IM_BADFORMAT]);
wrap_syslog (LOG_CRIT,"%s",syslog_message);
free (line);
if (have_oldline)
free (oldline);
exit (1);
break;
}
}
else if (gGammaMode)
ProduceGamma (image, line ) ; /* generate color calibration page */
if ( gTerminate )
{
/* this becomes true if EOF was obtained when a line was read .
* The input image is incomplete .
* Print only previously-read complete lines.
* unread lines are replaced with blanks for the rest of the print run
*/
int index ;
index = 0 ;
for ( i = 0 ; i < image->width ; i ++ )
{
line[index] = line[index + 1] = line[index + 2] = 255; ;
index += 3;
}
}
/* process ALL lines to avoid artifacts
(odd lines are only processed for black in *_Dither() functions )
hopefully, this minimal processing is quite fast */
if (gColorMode)
{
if (gFastMode)
HT_Color_Dither (image, line);
else
FS_Color_Dither (image, line);
}
else
HT_Black_Dither (image, line);
/* if the current line is odd, we only need to return black data */
if (image->bufferCurLine % 2 == 1)
{
if ( (!gEcoMode || gColorMode) && !gPixmapMode )
{
convert_black_data (image, line, &black[0][b_off]);
}
else
{
/* in B&W EcoMode, or in PixmapMode,
* don't print the odd line, but store it
* (unless this is the last line!)
*/
if ( image->bufferCurLine + 1 < image->height )
{
memset(&black[0] [b_off], 0x00, (image->width +7 ) / 8 );
oldline = malloc (image->width * 3);
memcpy(oldline, line, image->width * 3 );
have_oldline = 1;
}
}
}
else
{
/* return both black and color data on even lines */
/* note that convert_color_data must be called AFTER convert_black_data */
if ( have_oldline )
{
/* add any black from previous unprinted odd line
to next even line */
for ( i = 0; i < image->width * 3; i += 3 )
{
if ( !oldline[i] && !oldline[i + 1] && !oldline[i + 2] )
{
line[i] = line[i + 1] = line[i + 2] = 0 ;
}
}
free(oldline);
have_oldline = 0;
}
convert_black_data (image, line, &black[0][b_off]);
if (gColorMode)
convert_color_data (image, line, color, c_off);
}
free (line);
image->bufferCurLine++;
}
/* Drugo */
/* buffer a black line or two and return color data */
void
buffer_black_line (image_t *image, unsigned char *data[], int offset)
{
int lines, linesize = (image->width + 7) / 8;
/* if the current line is odd, we need to read 2 black lines */
if (image->bufferCurLine % 2 == 1)
lines = 2;
else
lines = 1; //mocho 1
remallocBuffer (image, linesize * lines);
/* read_line into buffer and 'data' */
read_line (image, image->buffer,
image->bufpos + image->buflines * linesize, data, offset);
image->buflines++;
/* if we have to read 2 lines, then we haven't gotten any color data yet */
if (lines == 2)
{
read_line (image, image->buffer,
image->bufpos + image->buflines * linesize, data, offset);
image->buflines++;
}
image->buftype = bitmap;
}
/* buffer a color line and return black data */
void
buffer_color_line (image_t *image, unsigned char *data[], int offset)
{
int linesize = (image->width / 2 + 7) / 8 * 3;
/* if the current line is odd, we don't need to buffer any color data */
if (image->bufferCurLine % 2 == 1)
{
read_line (image, data, offset, NULL, 0);
return;
}
/* we need to buffer 1 color line */
if (gColorMode)
remallocBuffer (image, linesize);
read_line (image, data, offset, image->buffer,
image->bufpos + image->buflines * linesize);
image->buflines++;
image->buftype = color;
}
/* Reads a single line of black image data into data which must be at least
(image->width+7)/8 bytes of storage */
int
im_black_readline (image_t *image, unsigned char *data[], int offset)
{
if (image->blackCurLine >= image->height)
return 0;
if (image->unread)
{
memcpy (data[0] + offset, image->revdata, (image->width + 7) / 8);
image->blackCurLine++;
image->unread = 0;
free (image->revdata);
return 1;
}
/* if there are buffered black lines, use one of them */
/* if there aren't buffered black lines, process the next line and */
/* buffer a color line */
if (image->buftype == bitmap)
{
memcpy (data[0] + offset,
&image->buffer[0][image->bufpos], (image->width + 7) / 8);
image->bufpos += (image->width + 7) / 8;
if (--image->buflines == 0)
{
image->bufpos = 0;
image->buftype = empty;
}
}
else
buffer_color_line (image, data, offset);
image->blackCurLine++;
return 1;
}
/* Reads a single line of color image data into data which must be at least
(image->width/2+7)/8*3 bytes of storage */
int
im_color_readline (image_t *image, unsigned char *data[], int offset)
{
int k;
if (image->colorCurLine >= image->height)
{
DPRINTF ("im_color_readline returning 0 immediately!\n");
return 0;
}
/* if there are buffered color lines, use one of them */
/* if there aren't buffered color lines, process the next line and */
/* buffer a black line */
if (image->buftype == color)
{
for (k = 0; k < gMaxPass; k++)
memcpy (data[k] + offset,
&image->buffer[k][image->bufpos], 3 * ((image->width / 2 + 7) / 8)); //mocho changes /2
image->bufpos += 3 * ((image->width / 2 + 7) / 8); //mocho changes /2
image->buflines--;
if (image->buflines == 0)
{
image->bufpos = 0;
image->buftype = empty;
}
}
else
buffer_black_line (image, data, offset);
image->colorCurLine += 2;
return 1;
}
/* push a black line back into the buffer; we read too much! */
void
im_unreadline (image_t * image, void *data)
{
/* can only store one line in the unread buffer */
if (image->unread)
return;
image->unread = 1;
image->revdata = malloc ((image->width + 7) / 8);
memcpy (image->revdata, data, (image->width + 7) / 8);
image->blackCurLine--;
}