Esempio n. 1
0
/* This routine is used for all formats. */
static int
png_print_page(gx_device_printer * pdev, FILE * file)
{
    gs_memory_t *mem = pdev->memory;
    int raster = gdev_prn_raster(pdev);

    /* PNG structures */
    byte *row = gs_alloc_bytes(mem, raster, "png raster buffer");
    png_struct *png_ptr =
    png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    png_info *info_ptr =
    png_create_info_struct(png_ptr);
    int height = pdev->height;
    int depth = pdev->color_info.depth;
    int y;
    int code;			/* return code */
    char software_key[80];
    char software_text[256];
    png_text text_png;

    if (row == 0 || png_ptr == 0 || info_ptr == 0) {
	code = gs_note_error(gs_error_VMerror);
	goto done;
    }
    /* set error handling */
    if (setjmp(png_ptr->jmpbuf)) {
	/* If we get here, we had a problem reading the file */
	code = gs_note_error(gs_error_VMerror);
	goto done;
    }
    code = 0;			/* for normal path */
    /* set up the output control */
    png_init_io(png_ptr, file);

    /* set the file information here */
    info_ptr->width = pdev->width;
    info_ptr->height = pdev->height;
    /* resolution is in pixels per meter vs. dpi */
    info_ptr->x_pixels_per_unit =
	(png_uint_32) (pdev->HWResolution[0] * (100.0 / 2.54));
    info_ptr->y_pixels_per_unit =
	(png_uint_32) (pdev->HWResolution[1] * (100.0 / 2.54));
    info_ptr->phys_unit_type = PNG_RESOLUTION_METER;
    info_ptr->valid |= PNG_INFO_pHYs;
    switch (depth) {
	case 32:
	    info_ptr->bit_depth = 8;
	    info_ptr->color_type = PNG_COLOR_TYPE_RGB_ALPHA;
	    png_set_invert_alpha(png_ptr);
	    {   gx_device_pngalpha *ppdev = (gx_device_pngalpha *)pdev;
		png_color_16 background;
		background.index = 0;
		background.red =   (ppdev->background >> 16) & 0xff;
		background.green = (ppdev->background >> 8)  & 0xff;
		background.blue =  (ppdev->background)       & 0xff;
		background.gray = 0;
		png_set_bKGD(png_ptr, info_ptr, &background);
	    }
	    break;
	case 48:
	    info_ptr->bit_depth = 16;
	    info_ptr->color_type = PNG_COLOR_TYPE_RGB;
#if defined(ARCH_IS_BIG_ENDIAN) && (!ARCH_IS_BIG_ENDIAN) 
	    png_set_swap(png_ptr);
#endif
	    break;
	case 24:
	    info_ptr->bit_depth = 8;
	    info_ptr->color_type = PNG_COLOR_TYPE_RGB;
	    break;
	case 8:
	    info_ptr->bit_depth = 8;
	    if (gx_device_has_color(pdev))
		info_ptr->color_type = PNG_COLOR_TYPE_PALETTE;
	    else
		info_ptr->color_type = PNG_COLOR_TYPE_GRAY;
	    break;
	case 4:
	    info_ptr->bit_depth = 4;
	    info_ptr->color_type = PNG_COLOR_TYPE_PALETTE;
	    break;
	case 1:
	    info_ptr->bit_depth = 1;
	    info_ptr->color_type = PNG_COLOR_TYPE_GRAY;
	    /* invert monocrome pixels */
	    png_set_invert_mono(png_ptr);
	    break;
    }

    /* set the palette if there is one */
    if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) {
	int i;
	int num_colors = 1 << depth;
	gx_color_value rgb[3];

	info_ptr->palette =
	    (void *)gs_alloc_bytes(mem, 256 * sizeof(png_color),
				   "png palette");
	if (info_ptr->palette == 0) {
	    code = gs_note_error(gs_error_VMerror);
	    goto done;
	}
	info_ptr->num_palette = num_colors;
	info_ptr->valid |= PNG_INFO_PLTE;
	for (i = 0; i < num_colors; i++) {
	    (*dev_proc(pdev, map_color_rgb)) ((gx_device *) pdev,
					      (gx_color_index) i, rgb);
	    info_ptr->palette[i].red = gx_color_value_to_byte(rgb[0]);
	    info_ptr->palette[i].green = gx_color_value_to_byte(rgb[1]);
	    info_ptr->palette[i].blue = gx_color_value_to_byte(rgb[2]);
	}
    }
    /* add comment */
    strncpy(software_key, "Software", sizeof(software_key));
    sprintf(software_text, "%s %d.%02d", gs_product,
	    (int)(gs_revision / 100), (int)(gs_revision % 100));
    text_png.compression = -1;	/* uncompressed */
    text_png.key = software_key;
    text_png.text = software_text;
    text_png.text_length = strlen(software_text);
    info_ptr->text = &text_png;
    info_ptr->num_text = 1;

    /* write the file information */
    png_write_info(png_ptr, info_ptr);

    /* don't write the comments twice */
    info_ptr->num_text = 0;
    info_ptr->text = NULL;

    /* Write the contents of the image. */
    for (y = 0; y < height; y++) {
	gdev_prn_copy_scan_lines(pdev, y, row, raster);
	png_write_rows(png_ptr, &row, 1);
    }

    /* write the rest of the file */
    png_write_end(png_ptr, info_ptr);

    /* if you alloced the palette, free it here */
    gs_free_object(mem, info_ptr->palette, "png palette");

  done:
    /* free the structures */
    png_destroy_write_struct(&png_ptr, &info_ptr);
    gs_free_object(mem, row, "png raster buffer");

    return code;
}
Esempio n. 2
0
/* one scan line at a time */
static int
win_pr2_print_page(gx_device_printer * pdev, FILE * file)
{
    int raster = gdev_prn_raster(pdev);

    /* BMP scan lines are padded to 32 bits. */
    ulong bmp_raster = raster + (-raster & 3);
    ulong bmp_raster_multi;
    int scan_lines, yslice, lines, i;
    int width;
    int depth = pdev->color_info.depth;
    byte *row;
    int y;
    int code = 0;		/* return code */
    MSG msg;
    char dlgtext[32];
    HGLOBAL hrow;
    int ratio = ((gx_device_win_pr2 *)pdev)->ratio;

    struct bmi_s {
	BITMAPINFOHEADER h;
	RGBQUAD pal[256];
    } bmi;

    scan_lines = dev_print_scan_lines(pdev);
    width = (int)(pdev->width - ((dev_l_margin(pdev) + dev_r_margin(pdev) -
				  dev_x_offset(pdev)) * pdev->x_pixels_per_inch));

    yslice = 65535 / bmp_raster;	/* max lines in 64k */
    bmp_raster_multi = bmp_raster * yslice;
    hrow = GlobalAlloc(0, bmp_raster_multi);
    row = GlobalLock(hrow);
    if (row == 0)		/* can't allocate row buffer */
	return_error(gs_error_VMerror);

    /* Write the info header. */

    bmi.h.biSize = sizeof(bmi.h);
    bmi.h.biWidth = pdev->width;	/* wdev->mdev.width; */
    bmi.h.biHeight = yslice;
    bmi.h.biPlanes = 1;
    bmi.h.biBitCount = pdev->color_info.depth;
    bmi.h.biCompression = 0;
    bmi.h.biSizeImage = 0;	/* default */
    bmi.h.biXPelsPerMeter = 0;	/* default */
    bmi.h.biYPelsPerMeter = 0;	/* default */

    StartPage(wdev->hdcprn);
    
    /* Write the palette. */

    if (depth <= 8) {
	int i;
	gx_color_value rgb[3];
	LPRGBQUAD pq;

	bmi.h.biClrUsed = 1 << depth;
	bmi.h.biClrImportant = 1 << depth;
	for (i = 0; i != 1 << depth; i++) {
	    (*dev_proc(pdev, map_color_rgb)) ((gx_device *) pdev,
					      (gx_color_index) i, rgb);
	    pq = &bmi.pal[i];
	    pq->rgbRed = gx_color_value_to_byte(rgb[0]);
	    pq->rgbGreen = gx_color_value_to_byte(rgb[1]);
	    pq->rgbBlue = gx_color_value_to_byte(rgb[2]);
	    pq->rgbReserved = 0;
	}
    } else {
	bmi.h.biClrUsed = 0;
	bmi.h.biClrImportant = 0;
    }

    if (!wdev->nocancel) {
	sprintf(dlgtext, "Printing page %d", (int)(pdev->PageCount) + 1);
	SetWindowText(GetDlgItem(wdev->hDlgModeless, CANCEL_PRINTING), dlgtext);
	ShowWindow(wdev->hDlgModeless, SW_SHOW);
    }
    for (y = 0; y < scan_lines;) {
	/* copy slice to row buffer */
	if (y > scan_lines - yslice)
	    lines = scan_lines - y;
	else
	    lines = yslice;
	for (i = 0; i < lines; i++)
	    gdev_prn_copy_scan_lines(pdev, y + i,
			      row + (bmp_raster * (lines - 1 - i)), raster);
	
	if (ratio > 1) {
	    StretchDIBits(wdev->hdcprn, 0, y*ratio, pdev->width*ratio, lines*ratio,
			  0, 0, pdev->width, lines,
			  row,
			  (BITMAPINFO FAR *) & bmi, DIB_RGB_COLORS, SRCCOPY);
	} else {
	    SetDIBitsToDevice(wdev->hdcprn, 0, y, pdev->width, lines,
			      0, 0, 0, lines,
			      row,
			      (BITMAPINFO FAR *) & bmi, DIB_RGB_COLORS);
	}
	y += lines;

	if (!wdev->nocancel) {
	    /* inform user of progress */
	    sprintf(dlgtext, "%d%% done", (int)(y * 100L / scan_lines));
	    SetWindowText(GetDlgItem(wdev->hDlgModeless, CANCEL_PCDONE), dlgtext);
	}
	/* process message loop */
	while (PeekMessage(&msg, wdev->hDlgModeless, 0, 0, PM_REMOVE)) {
	    if ((wdev->hDlgModeless == 0) || !IsDialogMessage(wdev->hDlgModeless, &msg)) {
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	    }
	}
	if ((!wdev->nocancel) && (wdev->hDlgModeless == 0)) {
	    /* user pressed cancel button */
	    break;
	}
    }

    if ((!wdev->nocancel) && (wdev->hDlgModeless == 0))
	code = gs_error_Fatal;	/* exit Ghostscript cleanly */
    else {
	/* push out the page */
	if (!wdev->nocancel)
	    SetWindowText(GetDlgItem(wdev->hDlgModeless, CANCEL_PCDONE),
			  "Ejecting page...");
	EndPage(wdev->hdcprn);
	if (!wdev->nocancel)
	    ShowWindow(wdev->hDlgModeless, SW_HIDE);
    }

    GlobalUnlock(hrow);
    GlobalFree(hrow);

    return code;
}
Esempio n. 3
0
/* Send the page to the printer. */
static int
jj100_print_page(gx_device_printer *pdev, FILE *prn_stream)
{	int line_size = gdev_prn_raster(pdev);
	int height = pdev->height;
	int bits_per_column = 48;
	int bytes_per_column = bits_per_column / 8;
	int chunk_size = bits_per_column * line_size;
	byte *in, *out;
	int lnum, skip;
	char prn_buf[16];

	in = (byte *)
		gs_malloc(gs_lib_ctx_get_non_gc_memory_t(), bits_per_column, line_size, "jj100_print_page(in)");
	out = (byte *)
		gs_malloc(gs_lib_ctx_get_non_gc_memory_t(), bits_per_column, line_size, "jj100_print_page(out)");
	if(in == 0 || out == 0)
		return -1;

	/* Initialize printer */
	fputs("\033P", pdev->file);	/* Proportional Mode */
        fputs("\033G", pdev->file);        /* 1/180 inch per line */
	fputs("\033T16", pdev->file);	/* 16/180 inch per line */

	/* Send Data to printer */
	lnum = 0;
	skip = 0;
	while(lnum < height) {
		byte *inp, *outp, *out_beg, *out_end;
		int x, y, num_lines, size, mod;

		/* Copy scan lines */
		if(gdev_prn_copy_scan_lines(pdev, lnum, in, chunk_size) < 0)
			break;

		/* The number of lines to process */
		if((num_lines = height - lnum) > bits_per_column)
			num_lines = bits_per_column;

		/* Test for all zero */
		size = line_size * num_lines;
		if(in[0] == 0 && 
		   !memcmp((char *)in, (char *)in + 1, size - 1)) {
			lnum += bits_per_column;
			skip ++;
			continue;
		}

		/* Fill zero */
		if(num_lines < bits_per_column) {
			size = line_size * (bits_per_column - num_lines);
			memset(in + line_size * num_lines, 0, size);
		}
		lnum += bits_per_column;

		/* Vertical tab to the appropriate position. */
		while(skip > 15) {
			sprintf(prn_buf, "\037%c", 16 + 15);
			fputs(prn_buf, pdev->file);
			skip -= 15;
		}
		if(skip > 0) {
			sprintf(prn_buf, "\037%c", 16 + skip);
			fputs(prn_buf, pdev->file);
		}

		/* Transpose in blocks of 8 scan lines. */
		for(y = 0; y < bytes_per_column; y ++) {
			inp = in + line_size * 8 * y;
			outp = out + y;
			for(x = 0; x < line_size; x ++) {
				jj100_transpose_8x8(inp, line_size,
						    outp, bytes_per_column);
				inp ++;
				outp += bits_per_column;
			}
		}

		/* Remove trailing 0s. */
		out_end = out + chunk_size - 1;
		while(out_end >= out) {
			if(*out_end)
				break;
			out_end --;
		}
		size = (out_end - out) + 1;
		if((mod = size % bytes_per_column) != 0)
			out_end += bytes_per_column - mod;

		/* Remove leading 0s. */
		out_beg = out;
		while(out_beg <= out_end) {
			if(*out_beg)
				break;
			out_beg ++;
		}
		out_beg -= (out_beg - out) % (bytes_per_column * 2);

		/* Dot addressing */
		sprintf(prn_buf, "\033F%04d", 
			(out_beg - out) / bytes_per_column / 2);
		fputs(prn_buf, pdev->file);

		/* Dot graphics */
		size = out_end - out_beg + 1;
		sprintf(prn_buf, "\034bP,48,%04d.", size / bytes_per_column);
		fputs(prn_buf, pdev->file);
		fwrite(out_beg, 1, size, pdev->file);

		/* Carriage Return */
		fputc('\r', pdev->file);
		skip = 1;
	}

	/* Form Feed */
	fputc('\f', pdev->file);
	fflush(pdev->file);

	gs_free(gs_lib_ctx_get_non_gc_memory_t(), (char *)out, 
		bits_per_column, line_size, "jj100_print_page(out)");
	gs_free(gs_lib_ctx_get_non_gc_memory_t(), (char *)in,
		bits_per_column, line_size, "jj100_print_page(in)");

	return 0;
}
Esempio n. 4
0
/* one scan line at a time */
static int
os2prn_print_page(gx_device_printer * pdev, FILE * file)
{
    int raster = gdev_prn_raster(pdev);

    /* BMP scan lines are padded to 32 bits. */
    ulong bmp_raster = (raster + 3) & (~3);
    ulong bmp_raster_multi;
    int height = pdev->height;
    int depth = pdev->color_info.depth;
    byte *row;
    int y;
    int code = 0;		/* return code */
    POINTL apts[4];
    APIRET rc;
    POINTL aptsb[4];
    HBITMAP hbmp, hbmr;
    int i, lines;
    int ystart, yend;
    int yslice;

    struct bmi_s {
	BITMAPINFOHEADER2 h;
	RGB2 pal[256];
    } bmi;

    yslice = 65535 / bmp_raster;
    bmp_raster_multi = bmp_raster * yslice;
    row = (byte *) gs_malloc(pdev->memory, bmp_raster_multi, 1, "bmp file buffer");
    if (row == 0)		/* can't allocate row buffer */
	return_error(gs_error_VMerror);

    if (opdev->newframe)
	DevEscape(opdev->hdc, DEVESC_NEWFRAME, 0L, NULL, NULL, NULL);
    opdev->newframe = 1;

    /* Write the info header. */

    memset(&bmi.h, 0, sizeof(bmi.h));
    bmi.h.cbFix = sizeof(bmi.h);
    bmi.h.cx = pdev->width;	/* opdev->mdev.width; */
    /* bmi.h.cy = height; */
    bmi.h.cy = yslice;		/* size for memory PS */
    bmi.h.cPlanes = 1;
    bmi.h.cBitCount = pdev->color_info.depth;

    /* Write the palette. */

    if (depth <= 8) {
	int i;
	gx_color_value rgb[3];
	PRGB2 pq;

	bmi.h.cclrUsed = 1 << depth;
	bmi.h.cclrImportant = 1 << depth;
	for (i = 0; i != 1 << depth; i++) {
	    (*dev_proc(pdev, map_color_rgb)) ((gx_device *) pdev,
					      (gx_color_index) i, rgb);
	    pq = &bmi.pal[i];
	    pq->bRed = gx_color_value_to_byte(rgb[0]);
	    pq->bGreen = gx_color_value_to_byte(rgb[1]);
	    pq->bBlue = gx_color_value_to_byte(rgb[2]);
	    pq->fcOptions = 0;
	}
    } else {
	bmi.h.cclrUsed = 0;
	bmi.h.cclrImportant = 0;
    }

    /* for GpiDrawBits */
    /* target is inclusive */
    apts[0].x = 0;
    apts[0].y = 0;		/* filled in later */
    apts[1].x = pdev->width - 1;
    apts[1].y = 0;		/* filled in later */
    /* source is not inclusive of top & right borders */
    apts[2].x = 0;
    apts[2].y = 0;
    apts[3].x = pdev->width;
    apts[3].y = 0;		/* filled in later */

    /* for GpiBitBlt */
    /* target is not inclusive */
    aptsb[0].x = opdev->clipbox[0];
    aptsb[0].y = 0;		/* filled in later */
    aptsb[1].x = opdev->clipbox[2];
    aptsb[1].y = 0;		/* filled in later */
    /* source is not inclusive */
    aptsb[2].x = opdev->clipbox[0];
    aptsb[2].y = 0;
    aptsb[3].x = opdev->clipbox[2];
    aptsb[3].y = 0;		/* filled in later */

    /* write the bits */
    ystart = opdev->clipbox[3];
    yend = opdev->clipbox[1];
    y = ystart;
    while (y > yend) {
	/* create a bitmap for the memory DC */
	hbmp = GpiCreateBitmap(opdev->hpsMem, &bmi.h, 0L, NULL, NULL);
	if (hbmp == GPI_ERROR)
	    goto bmp_done;
	hbmr = GpiSetBitmap(opdev->hpsMem, hbmp);

	/* copy slice to memory bitmap */
	if (y > yend + yslice)
	    lines = yslice;
	else
	    lines = y - yend;
	y -= lines;
	for (i = lines - 1; i >= 0; i--)
	    gdev_prn_copy_scan_lines(pdev, ystart - 1 - (y + i), row + (bmp_raster * i), raster);
	apts[0].y = 0;		/* target */
	apts[1].y = lines;
	apts[3].y = lines - 1;	/* source */
	/* copy DIB bitmap to memory bitmap */
	rc = GpiDrawBits(opdev->hpsMem, row, (BITMAPINFO2 *) & bmi, 4, apts,
			 (depth != 1) ? ROP_SRCCOPY : ROP_NOTSRCCOPY, 0);

	/* copy slice to printer */
	aptsb[0].y = y;
	aptsb[1].y = y + lines;
	aptsb[3].y = lines;
	rc = GpiBitBlt(opdev->hps, opdev->hpsMem, 4, aptsb, ROP_SRCCOPY, BBO_IGNORE);

	/* delete bitmap */
	if (hbmr != HBM_ERROR)
	    GpiSetBitmap(opdev->hpsMem, (ULONG) 0);
	hbmr = HBM_ERROR;
	if (hbmp != GPI_ERROR)
	    GpiDeleteBitmap(hbmp);
	hbmp = GPI_ERROR;
    }

  bmp_done:
    if (row)
	gs_free(pdev->memory, (char *)row, bmp_raster_multi, 1, "bmp file buffer");

    return code;
}
Esempio n. 5
0
/* Send the page to the printer. */
static int
cfax_stream_print_page_width(gx_device_printer * pdev, FILE * prn_stream,
                             const stream_template * temp, stream_state * ss,
                             int width)
{
    gs_memory_t *mem = pdev->memory;
    int code = 0;
    stream_cursor_read r;
    stream_cursor_write w;
    int in_size = gdev_prn_raster((gx_device *) pdev);
    /*
     * Because of the width adjustment for fax systems, width may
     * be different from (either greater than or less than) pdev->width.
     * Allocate a large enough buffer to account for this.
     */
    int col_size = (width * pdev->color_info.depth + 7) >> 3;
    int max_size = max(in_size, col_size);
    int lnum, nbytes, i;
    byte *in;
    byte *out;
    /* If the file is 'nul', don't even do the writes. */
    bool nul = !strcmp(pdev->fname, "nul");

    /* Initialize the common part of the encoder state. */
    ss->templat = temp;
    ss->memory = mem;

    /* Allocate the buffers. */
    in = gs_alloc_bytes(mem, temp->min_in_size + max_size + 1,
        "cfax_stream_print_page(in)");

#define OUT_SIZE 1000
    out = gs_alloc_bytes(mem, OUT_SIZE, "cfax_stream_print_page(out)");
    if (in == 0 || out == 0) {
        code = gs_note_error(gs_error_VMerror);
        goto done;
    }

    /* Process the image */
    for (lnum = 0; lnum < pdev->height; lnum++) {
        /* Initialize read and write pointer each time, because they're getting modified */
        r.ptr = in - 1;
        r.limit = in + col_size;
        w.ptr = out - 1;
        w.limit = w.ptr + OUT_SIZE;
        /* Decoder must encode line for line, so init it for each line */
        code = (*temp->init) (ss);
        if (code < 0)
            return_error(gs_error_limitcheck);
        /* Now, get the bits and encode them */
        gdev_prn_copy_scan_lines(pdev, lnum, in, in_size);
        if (col_size > in_size) {
            memset(in + in_size , 0, col_size - in_size);
        }
        code = (*temp->process) (ss, &r, &w, 1 /* always last line */);
        nbytes = w.ptr - out + 1;
        if (!nul) {
            if (nbytes > 0) {
                if (nbytes < 217) {
                    cfax_byte(nbytes, prn_stream);
                    for (i = 0; i < nbytes; i++)
                          cfax_byte(out[i], prn_stream);
                } else {
                    cfax_byte(0, prn_stream);
                    cfax_word(nbytes, prn_stream);
                    for (i = 0; i < nbytes; i++)
                          cfax_byte(out[i], prn_stream);
                }
            } else {
                cfax_byte(218, prn_stream);
            }
        }
        if (temp->release != 0)
            (*temp->release) (ss);
    }
#undef OUT_SIZE

  done:
    gs_free_object(mem, out, "cfax_stream_print_page(out)");
    gs_free_object(mem, in, "cfax_stream_print_page(in)");
    return code;
}
Esempio n. 6
0
int eprn_open_device(gx_device *device)
{
  eprn_Eprn *eprn = &((eprn_Device *)device)->eprn;
  const char *epref = eprn->CUPS_messages? CUPS_ERRPREF: "";
  int rc;

#ifdef EPRN_TRACE
  if_debug0(EPRN_TRACE_CHAR, "! eprn_open_device()...\n");
#endif

  /* Checks on page size and determination of derived values */
  if (eprn_set_page_layout((eprn_Device *)device) != 0)
    return_error(gs_error_rangecheck);

  /* Check the rendering parameters */
  if (eprn_check_colour_info(eprn->cap->colour_info, &eprn->colour_model,
      &device->HWResolution[0], &device->HWResolution[1],
      &eprn->black_levels, &eprn->non_black_levels) != 0) {
    gs_param_string str;

    eprintf1("%s" ERRPREF "The requested combination of colour model (",
      epref);
    str.size = 0;
    if (eprn_get_string(eprn->colour_model, eprn_colour_model_list, &str) != 0)
      assert(0); /* Bug. No harm on NDEBUG because I've just set the size. */
    errwrite(device->memory, (const char *)str.data, str.size * sizeof(str.data[0]));
    eprintf7("),\n"
      "%s  resolution (%gx%g ppi) and intensity levels (%d, %d) is\n"
      "%s  not supported by the %s.\n",
      epref, device->HWResolution[0], device->HWResolution[1],
      eprn->black_levels, eprn->non_black_levels, epref, eprn->cap->name);
    return_error(gs_error_rangecheck);
  }

  /* Initialization for colour rendering */
  if (device->color_info.num_components == 4) {
    /* Native colour space is 'DeviceCMYK' */
    set_dev_proc(device, map_rgb_color, NULL);

    if (eprn->intensity_rendering == eprn_IR_FloydSteinberg)
      set_dev_proc(device, map_cmyk_color, &eprn_map_cmyk_color_max);
    else if (device->color_info.max_gray > 1 || device->color_info.max_color > 1)
      set_dev_proc(device, map_cmyk_color, &eprn_map_cmyk_color_flex);
    else
      set_dev_proc(device, map_cmyk_color, &eprn_map_cmyk_color);

    if (eprn->intensity_rendering == eprn_IR_FloydSteinberg)
      set_dev_proc(device, map_rgb_color, &eprn_map_rgb_color_for_CMY_or_K_max);
    else if (device->color_info.max_gray > 1 || device->color_info.max_color > 1)
      set_dev_proc(device, map_rgb_color, &eprn_map_rgb_color_for_CMY_or_K_flex);
    else
      set_dev_proc(device, map_rgb_color, &eprn_map_rgb_color_for_CMY_or_K);

  }
  else {
    set_dev_proc(device, map_cmyk_color, NULL);

    if (eprn->colour_model == eprn_DeviceRGB) {
      if (eprn->intensity_rendering == eprn_IR_FloydSteinberg)
        set_dev_proc(device, map_rgb_color, &eprn_map_rgb_color_for_RGB_max);
      else if (device->color_info.max_color > 1)
        set_dev_proc(device, map_rgb_color, &eprn_map_rgb_color_for_RGB_flex);
      else
        set_dev_proc(device, map_rgb_color, &eprn_map_rgb_color_for_RGB);
    } else {
      if (eprn->intensity_rendering == eprn_IR_FloydSteinberg)
        set_dev_proc(device, map_rgb_color, &eprn_map_rgb_color_for_CMY_or_K_max);
      else if (device->color_info.max_gray > 1 || device->color_info.max_color > 1)
        set_dev_proc(device, map_rgb_color, &eprn_map_rgb_color_for_CMY_or_K_flex);
      else
        set_dev_proc(device, map_rgb_color, &eprn_map_rgb_color_for_CMY_or_K);
    }
  }
  eprn->output_planes = eprn_bits_for_levels(eprn->black_levels) +
    3 * eprn_bits_for_levels(eprn->non_black_levels);

#if !defined(GS_REVISION) || GS_REVISION >= 600
  /*  According to my understanding, the following call should be superfluous
      (because the colour mapping functions may not be called while the device
      is closed) and I am also not aware of any situation where it does make a
      difference. It shouldn't do any harm, though, and I feel safer with it :-)
  */
  gx_device_decache_colors(device);
#endif

#ifndef EPRN_NO_PAGECOUNTFILE
  /* Read the page count value */
  if (eprn->pagecount_file != NULL) {
    unsigned long count;
    if (pcf_getcount(eprn->pagecount_file, &count) == 0)
      device->PageCount = count;
       /* unsigned to signed. The C standard permits
          an implementation to generate an overflow indication if the value is
          too large. I consider this to mean that the type of 'PageCount' is
          inappropriate :-). Note that eprn does not use 'PageCount' for
          updating the file. */
    else {
      /* pcf_getcount() has issued an error message. */
      eprintf(
        "  No further attempts will be made to access the page count file.\n");
      gs_free(gs_lib_ctx_get_non_gc_memory_t(), eprn->pagecount_file, strlen(eprn->pagecount_file) + 1,
        sizeof(char), "eprn_open_device");
      eprn->pagecount_file = NULL;
    }
  }
#endif  /* !EPRN_NO_PAGECOUNTFILE */

  /* Open the "prn" device part */
  if ((rc = gdev_prn_open(device)) != 0) return rc;

  /* Just in case a previous open call failed in a derived device (note that
     'octets_per_line' is still the same as then): */
  if (eprn->scan_line.str != NULL)
    gs_free(gs_lib_ctx_get_non_gc_memory_t(), eprn->scan_line.str, eprn->octets_per_line, sizeof(eprn_Octet),
      "eprn_open_device");
  if (eprn->next_scan_line.str != NULL) {
    gs_free(gs_lib_ctx_get_non_gc_memory_t(), eprn->next_scan_line.str, eprn->octets_per_line, sizeof(eprn_Octet),
      "eprn_open_device");
    eprn->next_scan_line.str = NULL;
  }

  /* Calls which might depend on prn having been initialized */
  eprn->octets_per_line = gdev_prn_raster((gx_device_printer *)device);
  eprn->scan_line.str = (eprn_Octet *) gs_malloc(gs_lib_ctx_get_non_gc_memory_t(), eprn->octets_per_line,
    sizeof(eprn_Octet), "eprn_open_device");
  if (eprn->intensity_rendering == eprn_IR_FloydSteinberg) {
    eprn->next_scan_line.str = (eprn_Octet *) gs_malloc(gs_lib_ctx_get_non_gc_memory_t(), eprn->octets_per_line,
      sizeof(eprn_Octet), "eprn_open_device");
    if (eprn->next_scan_line.str == NULL && eprn->scan_line.str != NULL) {
      gs_free(gs_lib_ctx_get_non_gc_memory_t(), eprn->scan_line.str, eprn->octets_per_line, sizeof(eprn_Octet),
        "eprn_open_device");
      eprn->scan_line.str = NULL;
    }
  }
  if (eprn->scan_line.str == NULL) {
    eprintf1("%s" ERRPREF
      "Memory allocation failure from gs_malloc() in eprn_open_device().\n",
      epref);
    return_error(gs_error_VMerror);
  }

  return rc;
}