コード例 #1
0
ファイル: gdevcljc.c プロジェクト: BorodaZizitopa/ghostscript
/* Send the page to the printer.  Compress each scan line.  NB - the
 * render mode as well as color parameters - bpp etc. are all
 * hardwired.
 */
static int
cljc_print_page(gx_device_printer * pdev, FILE * prn_stream)
{
    gs_memory_t *mem = pdev->memory;
    uint raster = gx_device_raster((gx_device *)pdev, false);
    int i;
    int worst_case_comp_size = raster + (raster / 8) + 1;
    byte *data = 0;
    byte *cdata = 0;
    byte *prow = 0;
    int code = 0;

    /* allocate memory for the raw data and compressed data.  */
    if (((data = gs_alloc_bytes(mem, raster, "cljc_print_page(data)")) == 0) ||
        ((cdata = gs_alloc_bytes(mem, worst_case_comp_size, "cljc_print_page(cdata)")) == 0) ||
        ((prow = gs_alloc_bytes(mem, worst_case_comp_size, "cljc_print_page(prow)")) == 0)) {
        code = gs_note_error(gs_error_VMerror);
        goto out;
    }
    /* send a reset and the the paper definition */
    fprintf(prn_stream, "\033E\033&u300D\033&l%dA",
            gdev_pcl_paper_size((gx_device *) pdev));
    /* turn off source and pattern transparency */
    fprintf(prn_stream, "\033*v1N\033*v1O");
    /* set color render mode and the requested resolution */
    fprintf(prn_stream, "\033*t4J\033*t%dR", (int)(pdev->HWResolution[0]));
    /* set up the color model - NB currently hardwired to direct by
       pixel which requires 8 bits per component.  See PCL color
       technical reference manual for other possible encodings. */
    fprintf(prn_stream, "\033*v6W%c%c%c%c%c%c", 0, 3, 0, 8, 8, 8);
    /* set up raster width and height, compression mode 3 */
    fprintf(prn_stream, "\033&l0e-180u36Z\033*p0x0Y\033*r1A\033*b3M");
    /* initialize the seed row */
    memset(prow, 0, worst_case_comp_size);
    /* process each scanline */
    for (i = 0; i < pdev->height; i++) {
        int compressed_size;

        code = gdev_prn_copy_scan_lines(pdev, i, (byte *) data, raster);
        if (code < 0)
            break;
        compressed_size = gdev_pcl_mode3compress(raster, data, prow, cdata);
        fprintf(prn_stream, "\033*b%dW", compressed_size);
        fwrite(cdata, sizeof(byte), compressed_size, prn_stream);
    }
    /* PCL will take care of blank lines at the end */
    fputs("\033*rC\f", prn_stream);
out:
    gs_free_object(mem, prow, "cljc_print_page(prow)");
    gs_free_object(mem, cdata, "cljc_print_page(cdata)");
    gs_free_object(mem, data, "cljc_print_page(data)");
    return code;
}
コード例 #2
0
ファイル: gdevmiff.c プロジェクト: FRE3A/ruby-ghostscript
/* Print one page in 24-bit RLE direct color format. */
static int
miff24_print_page(gx_device_printer * pdev, FILE * file)
{
    int raster = gx_device_raster((gx_device *) pdev, true);
    byte *line = gs_alloc_bytes(pdev->memory, raster, "miff line buffer");
    int y;
    int code = 0;		/* return code */

    if (line == 0)		/* can't allocate line buffer */
        return_error(gs_error_VMerror);
    fputs("id=ImageMagick\n", file);
    fputs("class=DirectClass\n", file);
    fprintf(file, "columns=%d\n", pdev->width);
    fputs("compression=RunlengthEncoded\n", file);
    fprintf(file, "rows=%d\n", pdev->height);
    fputs(":\n", file);
    for (y = 0; y < pdev->height; ++y) {
        byte *row;
        byte *end;

        code = gdev_prn_get_bits(pdev, y, line, &row);
        if (code < 0)
            break;
        end = row + pdev->width * 3;
        while (row < end) {
            int count = 0;

            while (count < 255 && row < end - 3 &&
                   row[0] == row[3] && row[1] == row[4] &&
                   row[2] == row[5]
                )
                ++count, row += 3;
            putc(row[0], file);
            putc(row[1], file);
            putc(row[2], file);
            putc(count, file);
            row += 3;
        }
    }
    gs_free_object(pdev->memory, line, "miff line buffer");

    return code;
}
コード例 #3
0
/* rendering adjacent to the first band (forward or backward) */
static int
clist_get_bits_rect_mt(gx_device *dev, const gs_int_rect * prect,
			 gs_get_bits_params_t *params, gs_int_rect **unread)
{
    gx_device_printer *pdev = (gx_device_printer *)dev;
    gx_device_clist *cldev = (gx_device_clist *)dev;
    gx_device_clist_common *cdev = (gx_device_clist_common *)dev;
    gx_device_clist_reader *crdev = &cldev->reader;
    gs_memory_t *mem = cdev->bandlist_memory;
    gs_get_bits_options_t options = params->options;
    int y = prect->p.y;
    int end_y = prect->q.y;
    int line_count = end_y - y;
    int band_height = crdev->page_info.band_params.BandHeight;
    int band = y / band_height;
    gs_int_rect band_rect;
    int lines_rasterized;
    gx_device *bdev;
    byte *mdata;
    uint raster = bitmap_raster(dev->width * dev->color_info.depth);
    int my;
    int code = 0;

    /* This page might not want multiple threads */
    /* Also we don't support plane extraction using multiple threads */
    if (pdev->num_render_threads_requested < 1 || (options & GB_SELECT_PLANES))
	return clist_get_bits_rectangle(dev, prect, params, unread);

    if (prect->p.x < 0 || prect->q.x > dev->width ||
	y < 0 || end_y > dev->height
	)
	return_error(gs_error_rangecheck);
    if (line_count <= 0 || prect->p.x >= prect->q.x)
	return 0;

    if (crdev->ymin < 0) {
	if ((code = clist_close_writer_and_init_reader(cldev)) < 0)
	    return code;
	if (clist_setup_render_threads(dev, y) < 0) 
	    /* problem setting up the threads, revert to single threaded */
	    return clist_get_bits_rectangle(dev, prect, params, unread);
    }
    else {
	if (crdev->render_threads == NULL) {
            /* If we get here with with ymin >=0, it's because we closed the threads */
	    /* while doing a page due to an error. Use single threaded mode.         */
	    return clist_get_bits_rectangle(dev, prect, params, unread);
	}
    }
    /* If we already have the band's data, just return it */
    if (y < crdev->ymin || end_y > crdev->ymax)
	code = clist_get_band_from_thread(dev, band);
    if (code < 0)
	goto free_thread_out;
    mdata = crdev->data + crdev->page_tile_cache_size;
    if ((code = gdev_create_buf_device(cdev->buf_procs.create_buf_device,
				  &bdev, cdev->target, y, NULL,
				  mem, clist_get_band_complexity(dev,y))) < 0 ||
	(code = crdev->buf_procs.setup_buf_device(bdev, mdata, raster, NULL,
			    y - crdev->ymin, line_count, crdev->ymax - crdev->ymin)) < 0)
	goto free_thread_out;

    lines_rasterized = min(band_height, line_count);
    /* Return as much of the rectangle as falls within the rasterized lines. */
    band_rect = *prect;
    band_rect.p.y = 0;
    band_rect.q.y = lines_rasterized;
    code = dev_proc(bdev, get_bits_rectangle)
	(bdev, &band_rect, params, unread);
    cdev->buf_procs.destroy_buf_device(bdev);
    if (code < 0)
	goto free_thread_out;

    /* Note that if called via 'get_bits', the line count will always be 1 */
    if (lines_rasterized == line_count) {
	return code;		
    }

/***** TODO: Handle the below with data from the threads *****/
    /*
     * We'll have to return the rectangle in pieces.  Force GB_RETURN_COPY
     * rather than GB_RETURN_POINTER, and require all subsequent pieces to
     * use the same values as the first piece for all of the other format
     * options.  If copying isn't allowed, or if there are any unread
     * rectangles, punt.
     */
    if (!(options & GB_RETURN_COPY) || code > 0)
	return gx_default_get_bits_rectangle(dev, prect, params, unread);
    options = params->options;
    if (!(options & GB_RETURN_COPY)) {
	/* Redo the first piece with copying. */
	params->options = options =
	    (params->options & ~GB_RETURN_ALL) | GB_RETURN_COPY;
	lines_rasterized = 0;
    }
    {
	gs_get_bits_params_t band_params;
	uint raster = gx_device_raster(bdev, true);

	code = gdev_create_buf_device(cdev->buf_procs.create_buf_device,
				      &bdev, cdev->target, y, NULL,
				      mem, clist_get_band_complexity(dev, y));
	if (code < 0)
	    return code;
	band_params = *params;
	while ((y += lines_rasterized) < end_y) {
	    /* Increment data pointer by lines_rasterized. */
	    if (band_params.data)
		band_params.data[0] += raster * lines_rasterized;
	    line_count = end_y - y;
	    code = clist_rasterize_lines(dev, y, line_count, bdev, NULL, &my);
	    if (code < 0)
		break;
	    lines_rasterized = min(code, line_count);
	    band_rect.p.y = my;
	    band_rect.q.y = my + lines_rasterized;
	    code = dev_proc(bdev, get_bits_rectangle)
		(bdev, &band_rect, &band_params, unread);
	    if (code < 0)
		break;
	    params->options = options = band_params.options;
	    if (lines_rasterized == line_count)
		break;
	}
	cdev->buf_procs.destroy_buf_device(bdev);
    }
    return code;

/* Free up thread stuff */
free_thread_out:
    clist_teardown_render_threads(dev);
    return code;
}
コード例 #4
0
/* Send the page to the printer. */
static int
atx_print_page(gx_device_printer *pdev, FILE *f, int max_width_bytes)
{
    /*
     * The page length command uses 16 bits to represent the length in
     * units of 0.01", so the maximum representable page length is 
     * 655.35", including the unprintable top and bottom margins.
     * Compute the maximum height of the printable area in pixels.
     */
    float top_bottom_skip = (pdev->HWMargins[1] + pdev->HWMargins[3]) / 72.0;
    int max_height = (int)(pdev->HWResolution[1] * 655 - top_bottom_skip);
    int height = min(pdev->height, max_height);
    int page_length_100ths =
	(int)ceil((height / pdev->HWResolution[1] + top_bottom_skip) * 100);
    gs_memory_t *mem = pdev->memory;
    int raster = gx_device_raster((gx_device *)pdev, true);
    byte *buf;
    /*
     * ATX_COMPRESSED_DATA only takes a 1-byte (word) count.
     * Thus no compressed scan line can take more than 510 bytes.
     */
    int compressed_raster = min(raster / 2, 510); /* require 50% compression */
    byte *compressed;
    int blank_lines, lnum;
    int code = 0;

    /* Enforce a minimum 3" page length. */
    if (page_length_100ths < 300)
	page_length_100ths = 300;
    buf = gs_alloc_bytes(mem, raster, "atx_print_page(buf)");
    compressed = gs_alloc_bytes(mem, compressed_raster,
				"atx_print_page(compressed)");
    if (buf == 0 || compressed == 0) {
	code = gs_note_error(gs_error_VMerror);
	goto done;
    }
    fput_atx_command(f, ATX_SET_PAGE_LENGTH, page_length_100ths);
    for (blank_lines = 0, lnum = 0; lnum < height; ++lnum) {
	byte *row;
	byte *end;
	int count;

	gdev_prn_get_bits(pdev, lnum, buf, &row);
	/* Find the end of the non-blank data. */
	for (end = row + raster; end > row && end[-1] == 0 && end[-2] == 0; )
	    end -= 2;
	if (end == row) {		/* blank line */
	    ++blank_lines;
	    continue;
	}
	if (blank_lines) {		/* skip vertically */
	    fput_atx_command(f, ATX_VERTICAL_TAB, blank_lines + 1);
	    blank_lines = 0;
	}
	/* Truncate the line to the maximum printable width. */
	if (end - row > max_width_bytes)
	    end = row + max_width_bytes;
	count = atx_compress(row, end - row, compressed, compressed_raster);
	if (count >= 0) {		/* compressed line */
	    /*
	     * Note that since compressed_raster can't exceed 510, count
	     * can't exceed 510 either.
	     */
	    fputs(ATX_COMPRESSED_DATA, f);
	    fputc(count / 2, f);
	    fwrite(compressed, 1, count, f);
	} else {			/* uncompressed line */
	    int num_bytes = end - row;

	    fput_atx_command(f, ATX_UNCOMPRESSED_DATA, num_bytes);
	    fwrite(row, 1, num_bytes, f);
	}
    }

#if 0	/**************** MAY NOT BE NEEDED ****************/
    /* Enforce the minimum page length, and skip any final blank lines. */
    {
	int paper_length = (int)(pdev->HWResolution[1] * 3 + 0.5);
	int printed_length = height - blank_lines;

	if (height > paper_length)
	    paper_length = height;
	if (printed_length < paper_length)
	    fput_atx_command(f, ATX_VERTICAL_TAB,
			     paper_length - printed_length + 1);
    }
#endif

    /* End the page. */
    fputs(ATX_END_PAGE, f);

 done:
    gs_free_object(mem, compressed, "atx_print_page(compressed)");
    gs_free_object(mem, buf, "atx_print_page(buf)");
    return code;
}
コード例 #5
0
ファイル: gdevbj10.c プロジェクト: FRE3A/ruby-ghostscript
/* Send the page to the printer. */
static int
bj10e_print_page(gx_device_printer *pdev, FILE *prn_stream)
{	int line_size = gx_device_raster((gx_device *)pdev, 0);
        int xres = (int)pdev->x_pixels_per_inch;
        int yres = (int)pdev->y_pixels_per_inch;
        int mode = (yres == 180 ?
                        (xres == 180 ? 11 : 12) :
                        (xres == 180 ? 14 : 16));
        int bytes_per_column = (yres == 180) ? 3 : 6;
        int bits_per_column = bytes_per_column * 8;
        int skip_unit = bytes_per_column * 3;
        byte *in = (byte *)gs_malloc(pdev->memory, 8, line_size, "bj10e_print_page(in)");
        byte *out = (byte *)gs_malloc(pdev->memory, bits_per_column, line_size, "bj10e_print_page(out)");
        int lnum = 0;
        int skip = 0;
        int code = 0;
        int last_row = dev_print_scan_lines(pdev);
        int limit = last_row - bits_per_column;

        if ( in == 0 || out == 0 )
        {	code = gs_note_error(gs_error_VMerror);
                goto fin;
        }

        /* Initialize the printer. */
#ifdef USE_FACTORY_DEFAULTS
        /* Check for U.S. letter vs. A4 paper. */
        fwrite(( pdev->width / pdev->x_pixels_per_inch <= 8.4 ?
                "\033[K\002\000\000\044"	/*A4--DIP switch defaults*/ :
                "\033[K\002\000\004\044"	/*letter--factory defaults*/ ),
               1, 7, prn_stream);
#else
        fwrite("\033[K\002\000\000\044", 1, 7, prn_stream);
#endif

        /* Turn off automatic carriage return, otherwise we get line feeds. */
        fwrite("\0335\000", 1, 3, prn_stream);

        /* Set vertical spacing. */
        fwrite("\033[\\\004\000\000\000", 1, 7, prn_stream);
        fputc(yres & 0xff, prn_stream);
        fputc(yres >> 8, prn_stream);

        /* Set the page length.  This is the printable length, in inches. */
        fwrite("\033C\000", 1, 3, prn_stream);
        fputc((last_row + yres - 1)/yres, prn_stream);

        /* Transfer pixels to printer.  The last row we can print is defined
           by "last_row".  Only the bottom of the print head can print at the
           bottom margin, and so we align the final printing pass.  The print
           head is kept from moving below "limit", which is exactly one pass
           above the bottom margin.  Once it reaches this limit, we make our
           final printing pass of a full "bits_per_column" rows. */
        while ( lnum < last_row )
           {
                byte *in_data;
                byte *in_end = in + line_size;
                byte *out_beg = out;
                byte *out_end = out + bytes_per_column * pdev->width;
                byte *outl = out;
                int bnum;

                /* Copy 1 scan line and test for all zero. */
                code = gdev_prn_get_bits(pdev, lnum, in, &in_data);
                if ( code < 0 ) goto xit;
                /* The mem... or str... functions should be faster than */
                /* the following code, but all systems seem to implement */
                /* them so badly that this code is faster. */
                   {	register const long *zip = (const long *)in_data;
                        register int zcnt = line_size;
                        register const byte *zipb;
                        for ( ; zcnt >= 4 * sizeof(long); zip += 4, zcnt -= 4 * sizeof(long) )
                           {	if ( zip[0] | zip[1] | zip[2] | zip[3] )
                                        goto notz;
                           }
                        zipb = (const byte *)zip;
                        while ( --zcnt >= 0 )
                           {
                                if ( *zipb++ )
                                        goto notz;
                           }
                        /* Line is all zero, skip */
                        lnum++;
                        skip++;
                        continue;
notz:			;
                   }

                /* Vertical tab to the appropriate position.  Note here that
                   we make sure we don't move below limit. */
                if ( lnum > limit )
                    {	skip -= (lnum - limit);
                        lnum = limit;
                    }
                while ( skip > 255 )
                   {	fputs("\033J\377", prn_stream);
                        skip -= 255;
                   }
                if ( skip )
                        fprintf(prn_stream, "\033J%c", skip);

                /* If we've printed as far as "limit", then reset "limit"
                   to "last_row" for the final printing pass. */
                if ( lnum == limit )
                        limit = last_row;
                skip = 0;

                /* Transpose in blocks of 8 scan lines. */
                for ( bnum = 0; bnum < bits_per_column; bnum += 8 )
                   {	int lcnt = min(8, limit - lnum);
                        byte *inp = in;
                        byte *outp = outl;
                        lcnt = gdev_prn_copy_scan_lines(pdev,
                                lnum, in, lcnt * line_size);
                        if ( lcnt < 0 )
                           {	code = lcnt;
                                goto xit;
                           }
                        if ( lcnt < 8 )
                                memset(in + lcnt * line_size, 0,
                                       (8 - lcnt) * line_size);
                        for ( ; inp < in_end; inp++, outp += bits_per_column )
                           {	gdev_prn_transpose_8x8(inp, line_size,
                                        outp, bytes_per_column);
                           }
                        outl++;
                        lnum += lcnt;
                        skip += lcnt;
                   }

                /* Send the bits to the printer.  We alternate horizontal
                   skips with the data.  The horizontal skips are in units
                   of 1/120 inches, so we look at the data in groups of
                   3 columns, since 3/360 = 1/120, and 3/180 = 2/120.  */
                outl = out;
                do
                   {	int count;
                        int n;
                        byte *out_ptr;

                        /* First look for blank groups of columns. */
                        while(outl < out_end)
                           {	n = count = min(out_end - outl, skip_unit);
                                out_ptr = outl;
                                while ( --count >= 0 )
                                   {	if ( *out_ptr++ )
                                                break;
                                   }
                                if ( count >= 0 )
                                        break;
                                else
                                        outl = out_ptr;
                           }
                        if (outl >= out_end)
                                break;
                        if (outl > out_beg)
                           {	count = (outl - out_beg) / skip_unit;
                                if ( xres == 180 ) count <<= 1;
                                fprintf(prn_stream, "\033d%c%c",
                                        count & 0xff, count >> 8);
                           }

                        /* Next look for non-blank groups of columns. */
                        out_beg = outl;
                        outl += n;
                        while(outl < out_end)
                           {	n = count = min(out_end - outl, skip_unit);
                                out_ptr = outl;
                                while ( --count >= 0 )
                                   {	if ( *out_ptr++ )
                                                break;
                                   }
                                if ( count < 0 )
                                        break;
                                else
                                        outl += n;
                           }
                        count = outl - out_beg + 1;
                        fprintf(prn_stream, "\033[g%c%c%c",
                                count & 0xff, count >> 8, mode);
                        fwrite(out_beg, 1, count - 1, prn_stream);
                        out_beg = outl;
                        outl += n;
                   }
                while ( out_beg < out_end );

                fputc('\r', prn_stream);
           }
コード例 #6
0
ファイル: gdevsj48.c プロジェクト: computersforpeace/ghostpdl
/* Send the page to the printer. */
static int
sj48_print_page(gx_device_printer *pdev, FILE *prn_stream)
{	int line_size = gx_device_raster((gx_device *)pdev, 0);
        int xres = pdev->x_pixels_per_inch;
        int yres = pdev->y_pixels_per_inch;
        int mode = (yres == 180 ?
                        (xres == 180 ? 39 : 40) :
                        (xres == 180 ? 71 : 72));
        int bytes_per_column = (yres == 180) ? 3 : 6;
        int bits_per_column = bytes_per_column * 8;
        int skip_unit = bytes_per_column * (xres == 180 ? 1 : 2); /* Skips in step of 1/180" */
        byte *in = (byte *)gs_malloc(pdev->memory, 8, line_size, "sj48_print_page(in)");
        byte *out = (byte *)gs_malloc(pdev->memory, bits_per_column, line_size, "sj48_print_page(out)");
        int lnum = 0;
        int skip = 0;
        int skips;
        int code = 0;
        int last_row = dev_print_scan_lines(pdev);
        int limit = last_row - bits_per_column;

        if ( in == 0 || out == 0 )
        {	code = gs_error_VMerror;
                gs_note_error(code);
                goto fin;
        }

        /* Abort if the requested resolution is unsupported. */
        if ((xres !=180 && xres != 360) || (yres !=180 && yres != 360))
        {	code = gs_error_rangecheck;
                gs_note_error(code);
                goto fin;
        }

        /* Initialize the printer. */
        fwrite("\033@\000\000", 1, 4, prn_stream);  /* <Printer reset>, <0>, <0>. */

        /* Transfer pixels to printer.  The last row we can print is defined
           by "last_row".  Only the bottom of the print head can print at the
           bottom margin, and so we align the final printing pass.  The print
           head is kept from moving below "limit", which is exactly one pass
           above the bottom margin.  Once it reaches this limit, we make our
           final printing pass of a full "bits_per_column" rows. */
        while ( lnum < last_row )
           {
                byte *in_data;
                byte *in_end = in + line_size;
                byte *out_beg = out;
                byte *out_end = out + bytes_per_column * pdev->width;
                byte *outl = out;
                int bnum;

                /* Copy 1 scan line and test for all zero. */
                code = gdev_prn_get_bits(pdev, lnum, in, &in_data);
                if ( code < 0 ) goto xit;
                /* The mem... or str... functions should be faster than */
                /* the following code, but all systems seem to implement */
                /* them so badly that this code is faster. */
                   {	register const long *zip = (const long *)in_data;
                        register int zcnt = line_size;
                        register const byte *zipb;
                        for ( ; zcnt >= 4 * sizeof(long); zip += 4, zcnt -= 4 * sizeof(long) )
                           {	if ( zip[0] | zip[1] | zip[2] | zip[3] )
                                        goto notz;
                           }
                        zipb = (const byte *)zip;
                        while ( --zcnt >= 0 )
                           {
                                if ( *zipb++ )
                                        goto notz;
                           }
                        /* Line is all zero, skip */
                        lnum++;
                        skip++;
                        continue;
notz:			;
                   }

                /* Vertical tab to the appropriate position.  Note here that
                   we make sure we don't move below limit. */
                if ( lnum > limit )
                    {	skip -= (limit - lnum);
                        lnum = limit;
                    }

                /* The SJ48 can only skip in steps of 1/180" */
                if (yres == 180) {
                  skips = skip;
                } else {
                  if (skip & 1) {
                    skip--; /* Makes skip even. */
                    lnum--;
                  }
                  skips = skip/2;
                }

                while ( skips > 255 )
                   {	fputs("\033J\377", prn_stream);
                        skips -= 255;
                   }
                if ( skips )
                        fprintf(prn_stream, "\033J%c", skips);

                /* If we've printed as far as "limit", then reset "limit"
                   to "last_row" for the final printing pass. */
                if ( lnum == limit )
                        limit = last_row;
                skip = 0;

                /* Transpose in blocks of 8 scan lines. */
                for ( bnum = 0; bnum < bits_per_column; bnum += 8 )
                   {	int lcnt = min(8, limit - lnum);
                        byte *inp = in;
                        byte *outp = outl;
                        lcnt = gdev_prn_copy_scan_lines(pdev,
                                lnum, in, lcnt * line_size);
                        if ( lcnt < 0 )
                           {	code = lcnt;
                                goto xit;
                           }
                        if ( lcnt < 8 )
                                memset(in + lcnt * line_size, 0,
                                       (8 - lcnt) * line_size);
                        for ( ; inp < in_end; inp++, outp += bits_per_column )
                           {	gdev_prn_transpose_8x8(inp, line_size,
                                        outp, bytes_per_column);
                           }
                        outl++;
                        lnum += lcnt;
                        skip += lcnt;
                   }

                /* Send the bits to the printer.  We alternate horizontal
                   skips with the data.  The horizontal skips are in units
                   of 1/180 inches, so we look at the data in groups of
                   1 or 2 columns depending on resolution (controlled
                   by skip_unit).  */
                outl = out;
                do
                   {	int count;
                        int n;
                        byte *out_ptr;

                        /* First look for blank groups of columns. */
                        while(outl < out_end)
                           {	n = count = min(out_end - outl, skip_unit);
                                out_ptr = outl;
                                while ( --count >= 0 )
                                   {	if ( *out_ptr++ )
                                                break;
                                   }
                                if ( count >= 0 )
                                        break;
                                else
                                        outl = out_ptr;
                           }
                        if (outl >= out_end)
                                break;
                        if (outl > out_beg)
                           {	count = (outl - out_beg) / skip_unit;
                                fprintf(prn_stream, "\033\\%c%c",
                                        count & 0xff, count >> 8);
                           }

                        /* Next look for non-blank groups of columns. */
                        out_beg = outl;
                        outl += n;
                        while(outl < out_end)
                           {	n = count = min(out_end - outl, skip_unit);
                                out_ptr = outl;
                                while ( --count >= 0 )
                                   {	if ( *out_ptr++ )
                                                break;
                                   }
                                if ( count < 0 )
                                        break;
                                else
                                        outl += n;
                           }
                        count = outl - out_beg;
                        {
                          /* What to transmit is the number of columns in the row.
                             Compare this with the <Esc>|*-command wich expects the
                             total number of bytes in the graphic row! */
                          int count1 = count/bytes_per_column;
                          fprintf(prn_stream, "\033*%c%c%c",
                                  mode, count1 & 0xff, count1 >> 8);
                        }
                        fwrite(out_beg, 1, count, prn_stream);
                        out_beg = outl;
                        outl += n;
                   }
                while ( out_beg < out_end );

                fputc('\r', prn_stream);
                skip = bits_per_column;  /* <CR> only moves to the beginning of the row. */
           }