static void split_Gray(eprn_OctetString *line, eprn_OctetString *next_line, int max_octets, unsigned int black_levels, eprn_OctetString bitplanes[]) { const int max_pixel = max_octets - 1, planes = eprn_bits_for_levels(black_levels); int correction, error, new_value, pixel, pixel_mod_8, pixels = line->length, plane, remaining_error; eprn_Octet approx, *from, *ptr[8], *to; const unsigned int divisor = 256/black_levels, max_level = black_levels - 1; for (plane = 0; plane < planes; plane++) ptr[plane] = bitplanes[plane].str; /* Loop over pixels in the scan line. Note that 'pixels' may increase within the loop. */ for (pixel = 0, pixel_mod_8 = 8; pixel < pixels; pixel++, pixel_mod_8++) { if (pixel_mod_8 == 8) { pixel_mod_8 = 0; for (plane = 0; plane < planes; plane++) *ptr[plane] = 0; } /* Determine approximation and error for this pixel */ from = line->str + pixel; approx = *from/divisor; error = *from - (255*approx)/max_level; /* The sign of 'error' is chosen such that 'error' is positive if colorant intensity has to be added to the picture. */ /* Distribute the approximation over the bit planes */ for (plane = 0; plane < planes; plane++) { *ptr[plane] = (*ptr[plane] << 1) | approx & 0x01; approx >>= 1; } error_propagation_Gray() if (pixel_mod_8 == 7) for (plane = 0; plane < planes; plane++) ptr[plane]++; } eprn_finalize(false, 0, planes, bitplanes, ptr, pixels); return; }
void eprn_finalize(bool is_RGB, unsigned int non_black_levels, int planes, eprn_OctetString *plane, eprn_Octet **ptr, int pixels) { int j; /* Execute remaining left shifts in the last octet of the output planes when the number of pixels is not a multiple of 8, and fill with white on the right */ if (pixels % 8 != 0) { int shift = 8 - pixels % 8; if (is_RGB) { /* White may be any intensity, but it's the same for all three colorants, and it's the highest. */ eprn_Octet imax = non_black_levels - 1; int c, rgb_planes = eprn_bits_for_levels(non_black_levels); j = 0; /* next output plane */ /* Loop over RGB */ for (c = 0; c < 3; c++) { eprn_Octet value = imax; int m; /* Loop over all planes for this colorant */ for (m = 0; m < rgb_planes; m++, j++) { eprn_Octet bit = value & 1; int p; value = value >> 1; /* Put the bit into all remaining pixels for this plane */ for (p = 0; p < shift; p++) *ptr[j] = (*ptr[j] << 1) | bit; } } } else /* White is zero */ for (j = 0; j < planes; j++)
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(device->memory->non_gc_memory, 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(device->memory->non_gc_memory, eprn->scan_line.str, eprn->octets_per_line, sizeof(eprn_Octet), "eprn_open_device"); if (eprn->next_scan_line.str != NULL) { gs_free(device->memory->non_gc_memory, 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(device->memory->non_gc_memory, 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(device->memory->non_gc_memory, eprn->octets_per_line, sizeof(eprn_Octet), "eprn_open_device"); if (eprn->next_scan_line.str == NULL && eprn->scan_line.str != NULL) { gs_free(device->memory->non_gc_memory, 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; }
static void split_colour(eprn_OctetString *line, eprn_OctetString *next_line, int max_octets, eprn_ColourModel colour_model, unsigned int black_levels, unsigned int non_black_levels, eprn_OctetString bitplanes[]) { const int black_planes = eprn_bits_for_levels(black_levels), last_colorant = black_levels > 0? BLACK_INDEX: 2, max_pixel = max_octets/OCTETS_PER_PIXEL - 1, non_black_planes = eprn_bits_for_levels(non_black_levels), planes = black_planes + 3*non_black_planes; int colorant, correction, error, new_value, next_plane[4], pixel, pixel_mod_8, pixels = line->length/OCTETS_PER_PIXEL, plane, remaining_error; eprn_Octet approx[4], *from, *ptr[32], *to; unsigned int divisor[4], max_level[4]; if (black_levels > 0) { divisor[BLACK_INDEX] = 256/black_levels; max_level[BLACK_INDEX] = black_levels - 1; } else { divisor[BLACK_INDEX] = 0; max_level[BLACK_INDEX] = 0; } next_plane[BLACK_INDEX] = black_planes; for (colorant = 0; colorant < BLACK_INDEX; colorant++) { divisor[colorant] = 256/non_black_levels; max_level[colorant] = non_black_levels - 1; next_plane[colorant] = (3 - colorant)*non_black_planes + black_planes; } for (plane = 0; plane < planes; plane++) ptr[plane] = bitplanes[plane].str; /* Loop over pixels in the scan line. Note that 'pixels' may increase within the loop. */ for (pixel = 0, pixel_mod_8 = 8; pixel < pixels; pixel++, pixel_mod_8++) { if (pixel_mod_8 == 8) { pixel_mod_8 = 0; for (plane = 0; plane < planes; plane++) *ptr[plane] = 0; } /* Loop over colorants within a scan line */ for (colorant = last_colorant; colorant >= 0; colorant--) { from = line->str + pixel*OCTETS_PER_PIXEL + colorant; /* Determine approximation and error for this pixel */ approx[colorant] = *from/divisor[colorant]; error = *from - (255*approx[colorant])/max_level[colorant]; /* The sign of 'error' is chosen such that 'error' is positive if colorant intensity has to be added to the picture. */ error_propagation_colour() } /* Determine the black component for CMY+K */ if (colour_model == eprn_DeviceCMY_plus_K && approx[0] == approx[1] && approx[1] == approx[2] && approx[0] > 0) { int value = approx[0]*(black_levels - 1); if (value % (non_black_levels - 1) == 0) { /* Black does have a level at the same intensity as the CMY levels */ approx[BLACK_INDEX] = value/(non_black_levels - 1); approx[0] = approx[1] = approx[2] = 0; } } /* Distribute the approximation over the bit planes */ plane = 0; for (colorant = last_colorant; colorant >= 0; colorant--) { while (plane < next_plane[colorant]) { *ptr[plane] = (*ptr[plane] << 1) | approx[colorant] & 0x01; approx[colorant] >>= 1; plane++; } } if (pixel_mod_8 == 7) { int j; for (j = 0; j < planes; j++) ptr[j]++; } } eprn_finalize(colour_model == eprn_DeviceRGB, non_black_levels, planes, bitplanes, ptr, pixels); return; }