예제 #1
0
static int
do_page_load(gx_device_printer *pdev, gx_saved_page *page, clist_file_ptr *save_files)
{
    int code;
    gx_device_clist_reader *crdev = (gx_device_clist_reader *)pdev;
    gs_c_param_list paramlist;

    /* fetch and put the params we saved with the page */
    gs_c_param_list_write(&paramlist, pdev->memory);
    if ((code = gs_param_list_unserialize((gs_param_list *)&paramlist, page->paramlist)) < 0)
        goto out;
    gs_c_param_list_read(&paramlist);
    code = gs_putdeviceparams((gx_device *)pdev, (gs_param_list *)&paramlist);
    gs_c_param_list_release(&paramlist);
    if (code < 0) {
        goto out;
    }
    if (code > 0)
        if ((code = gs_opendevice((gx_device *)pdev)) < 0)
            goto out;

    /* If the device is now a writer, that means putparams realloced the device */
    /* so we need to get back to reader mode and remove the extra clist files  */
    if (CLIST_IS_WRITER((gx_device_clist *)pdev)) {
        clist_close_writer_and_init_reader((gx_device_clist *)crdev);
        /* close and unlink the temp files just created */
        if (crdev->page_info.cfile != NULL)
            crdev->page_info.io_procs->fclose(crdev->page_info.cfile, crdev->page_info.cfname, true);
        if (crdev->page_info.bfile != NULL)
            crdev->page_info.io_procs->fclose(crdev->page_info.bfile, crdev->page_info.bfname, true);
        crdev->page_info.cfile = crdev->page_info.bfile = NULL;
    }

    /* set up the page_info, after putdeviceparams that may have changed things */
    crdev->page_info.io_procs = page->io_procs;
    crdev->page_info.tile_cache_size = page->tile_cache_size;
    crdev->page_info.bfile_end_pos = page->bfile_end_pos;
    crdev->page_info.band_params = page->band_params;

    crdev->yplane.index = -1;
    crdev->pages = NULL;
    crdev->num_pages = 1;		/* single page at a time */
    crdev->offset_map = NULL;
    crdev->render_threads = NULL;
    crdev->ymin = crdev->ymax = 0;      /* invalidate buffer contents to force rasterizing */

    /* We probably don't need to copy in the filenames, but do it in case something expects it */
    strncpy(crdev->page_info.cfname, page->cfname, sizeof(crdev->page_info.cfname));
    strncpy(crdev->page_info.bfname, page->bfname, sizeof(crdev->page_info.bfname));
    if (save_files != NULL)
    {
        crdev->page_info.cfile = save_files[0];
        crdev->page_info.bfile = save_files[1];
    }
out:
    return code;
}
예제 #2
0
static int
clist_process_page_mt(gx_device *dev, gx_process_page_options_t *options)
{
    gx_device_printer *pdev = (gx_device_printer *)dev;
    gx_device_clist *cldev = (gx_device_clist *)dev;
    gx_device_clist_reader *crdev = &cldev->reader;
    int band_height = crdev->page_info.band_params.BandHeight;
    int band;
    int num_bands = (dev->height + band_height-1)/band_height;
    int code;
    int reverse = !!(options->options & GX_PROCPAGE_BOTTOM_UP);

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

    if ((code = clist_close_writer_and_init_reader(cldev)) < 0)
        return code;	/* can't recover from this */

    /* Haven't done any rendering yet, try to set up the threads */
    if (clist_setup_render_threads(dev, reverse ? dev->height-1 : 0, options) < 0)
        /* problem setting up the threads, revert to single threaded */
        return clist_process_page(dev, options);

    if (reverse)
    {
        for (band = num_bands-1; band > 0; band--)
        {
            code = clist_get_band_from_thread(dev, band, options);
            if (code < 0)
                goto free_thread_out;
        }
    }
    else
    {
        for (band = 0; band < num_bands; band++)
        {
            code = clist_get_band_from_thread(dev, band, options);
            if (code < 0)
                goto free_thread_out;
        }
    }

    /* Always free up thread stuff before exiting*/
free_thread_out:
    clist_teardown_render_threads(dev);
    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
int
clist_process_page(gx_device *dev, gx_process_page_options_t *options)
{
    gx_device_clist *cldev = (gx_device_clist *)dev;
    gx_device_clist_reader *crdev = &cldev->reader;
    gx_device_clist_common *cdev = (gx_device_clist_common *)dev;
    int y;
    int line_count;
    int band_height = crdev->page_band_height;
    gs_int_rect band_rect;
    int lines_rasterized;
    gx_device *bdev;
    gx_render_plane_t render_plane;
    int my;
    int code;
    void *buffer = NULL;

    if (0 > (code = clist_close_writer_and_init_reader(cldev)))
        return code;

    if (options->init_buffer_fn) {
        code = options->init_buffer_fn(options->arg, dev, dev->memory, dev->width, band_height, &buffer);
        if (code < 0)
            return code;
    }

    render_plane.index = -1;
    for (y = 0; y < dev->height; y += lines_rasterized)
    {
        line_count = band_height;
        if (line_count > dev->height - y)
            line_count = dev->height - y;
        code = gdev_create_buf_device(cdev->buf_procs.create_buf_device,
                                      &bdev, cdev->target, y, &render_plane,
                                      dev->memory,
                                      &(crdev->color_usage_array[y/band_height]));
        if (code < 0)
            return code;
        code = clist_rasterize_lines(dev, y, line_count, bdev, &render_plane, &my);
        if (code >= 0)
        {
            lines_rasterized = min(code, line_count);

            /* Return as much of the rectangle as falls within the rasterized lines. */
            band_rect.p.x = 0;
            band_rect.p.y = y;
            band_rect.q.x = dev->width;
            band_rect.q.y = y + lines_rasterized;
            if (options->process_fn)
                code = options->process_fn(options->arg, dev, bdev, &band_rect, buffer);
        }
        if (code >= 0 && options->output_fn)
            code = options->output_fn(options->arg, dev, buffer);
        cdev->buf_procs.destroy_buf_device(bdev);
        if (code < 0)
            break;
    }

    if (options->free_buffer_fn) {
        options->free_buffer_fn(options->arg, dev, dev->memory, buffer);
    }

    return code;
}
예제 #5
0
/*
 * Print selected pages from the list to on the selected device. The
 * saved_pages_list is NOT modified, allowing for reprint / recovery
 * print. Each saved_page is printed on a separate page (unlike the
 * gdev_prn_render_pages above which prints several saved_pages on
 * a single "master" page, performing imposition).
 *
 * This is primarily intended to allow printing in non-standard order
 * (reverse, odd, even) or producing collated copies for a job.
 *
 * On success return the number of bytes consumed or error code < 0.
 * The printed_count will contain the number of pages printed.
 *
 * -------------------------------------------------------------------
 *
 * The param string may begin with whitespace. The string is parsed
 * and the selected pages are printed. There may be any number of ranges
 * and or keywords separated by whitespace and/or comma ','.
 *
 * NB: The pdev printer device's PageCount is updated to reflect the
 *     total number of pages produced (per the spec for this parameter)
 *     since we may be producing multiple collated copies.
 *     Also the list PageCount is updated after printing since
 *     there may be a subsequent 'print' action.
 * keywords:
 *	copies #	Set the number of copies for subsequent printing actions
 *                      "copies 1" resets to a single copy
 *	normal		All pages are printed in normal order
 *	reverse		All pages are printed in reverse order
 *         The following two options may be useful for duplexing.
 *	odd		All odd pages are printed, e.g. 1, 3, 5, ...
 *	even		All even pages are printed, e.g. 2, 4, 6, ...
 *                      NB: an extra blank page will be printed if the list
 *                      has an odd number of pages.
 *      even0pad        All even pages, but no extra blank page if there are
 *                      an odd number of pages on the list.
 * range syntax:
 *	range range	multiple ranges are separated by commas ','
 *			and/or whitespace.
 *	#		a specific page number is a valid range
 *
 *	inclusive ranges below can have whitespace before
 *	or after the dash '-'.
 *	#-#		a range consisting of all pages from the first
 *			page # up to (and including) the second page #.
 *	#-*		all pages from # up through the last page
 *			"1-*" is equivalent to "normal"
 *	*-#		all pages from the last up through # page.
 *			"reverse" is equivalent to "*-1"
 */
int
gx_saved_pages_list_print(gx_device_printer *pdev, gx_saved_pages_list *list,
                          byte *param, int param_size, int *printed_count)
{
    byte *param_scan = NULL;
    int param_left;
    int start_page = 0;				/* 0 means start_page unknown */
    int end_page = 0;				/* < 0 means waiting for the end of a # - # range */
                                                /* i.e, a '-' was scanned. 0 means unknown */
    int tmp_num;				/* during token scanning loop */
    int code = 0, endcode = 0;
    byte *token;
    int copy, token_size;
    gx_device_clist_reader *crdev = (gx_device_clist_reader *)pdev;
    /* the following are used so we can go back to the original state */
    bool save_bg_print = false;                 /* arbitrary, silence warning */
    bool save_bandfile_open_close = false;      /* arbitrary, silence warning */
    gx_saved_page saved_page;
    clist_file_ptr saved_files[2];

    /* save the current (empty) page while we print  */
    if ((code = do_page_save(pdev, &saved_page, saved_files)) < 0) {
        emprintf(pdev->memory, "gx_saved_pages_list_print: Error getting device params\n");
        goto out;
    }

    /* save_page leaves the clist in writer mode, so prepare for reading clist */
    /* files. When we are done with printing, we'll go back to write mode.     */
    if ((code = clist_close_writer_and_init_reader((gx_device_clist *)pdev)) < 0)
        goto out;

    /* While printing, disable the saved_pages mode and bg_print */
    pdev->saved_pages_list = NULL;
    save_bg_print = pdev->bg_print_requested;

    /* Inhibits modifying the clist at end of output_page */
    save_bandfile_open_close = crdev->do_not_open_or_close_bandfiles;
    crdev->do_not_open_or_close_bandfiles = true;

    pdev->PageCount = list->PageCount;		/* adjust to value last printed */

    /* loop producing the number of copies */
    /* Note: list->collated_copies may change if 'copies' param follows the 'print' */
    for (copy = 1; copy <= list->collated_copies; copy++) {
        int page_skip = 0;
        bool do_blank_page_pad;
        int page;

        /* Set to start of 'print' params to do collated copies */
        param_scan = param;
        param_left = param_size;
        while ((token = param_parse_token(param_scan, param_left, &token_size)) != NULL) {
            saved_pages_key_enum key;

            page = 0;
            do_blank_page_pad = false;			/* only set for EVEN */
            key = param_find_key(token, token_size);
            switch (key) {
              case PARAM_DASH:
                if (start_page == 0) {
                    emprintf(pdev->memory, "gx_saved_pages_list_print: '-' unexpected\n");
                    code = gs_error_typecheck;
                    goto out;
                }
                end_page = -1;		/* the next number will end a range */
                break;

              case PARAM_STAR:
                page = list->count;		/* last page */
              case PARAM_NUMBER:
                if (page == 0) {
                     if (sscanf((const char *)token, "%d", &page) != 1) {
                         emprintf1(pdev->memory, "gx_saved_pages_list_print: Number format error '%s'\n", token);
                         code = gs_error_typecheck;
                         goto out;
                     }
                }
                if (start_page == 0) {
                    start_page = page;		/* first number seen */
                } else {
                    /* a second number was seen after the start_page was set */
                    if (end_page < 0) {
                        end_page = page;		/* end of a '# - #' range */
                        page_skip = (end_page >= start_page) ? 1 : -1;
                    } else {
                        /* 'page' was NOT part of a range after printing 'page' will start a new range */
                        end_page = start_page;	/* single page */
                        page_skip = 1;
                    }
                }
                break;

              case PARAM_COPIES:			/* copies requires a number next */
                /* Move to past 'copies' token */
                param_left -= token - param_scan + token_size;
                param_scan = token + token_size;

                if ((token = param_parse_token(param_scan, param_left, &token_size)) == NULL ||
                     param_find_key(token, token_size) != PARAM_NUMBER) {
                    emprintf(pdev->memory, "gx_saved_pages_list_print: copies not followed by number.\n");
                    code = gs_error_typecheck;
                    goto out;
                }
                if (sscanf((const char *)token, "%d", &tmp_num) != 1) {
                    emprintf1(pdev->memory, "gx_saved_pages_list_print: Number format error '%s'\n", token);
                    code = gs_error_typecheck;
                    goto out;
                }
                list->collated_copies = tmp_num;	/* save it for our loop */
                break;

              case PARAM_NORMAL:			/* sets both start and end */
                start_page = 1;
                end_page = list->count;
                page_skip = 1;
                break ;

              case PARAM_REVERSE:			/* sets both start and end */
                start_page = list->count;
                end_page = 1;
                page_skip = -1;
                break;

              case PARAM_EVEN:			/* sets both start and end */
                do_blank_page_pad = (list->count & 1) != 0;	/* pad if odd */
              case PARAM_EVEN0PAD:		/* sets both start and end */
                start_page = 2;
                end_page = list->count;
                page_skip = 2;
                break ;

              case PARAM_ODD:			/* sets both start and end */
                start_page = 1;
                end_page = list->count;
                page_skip = 2;
                break ;

              case PARAM_UNKNOWN:
              case PARAM_BEGIN:
              case PARAM_END:
              case PARAM_FLUSH:
              case PARAM_PRINT:
                token_size = 0;			/* non-print range token seen */
            }
            if (end_page > 0) {
                /* Here we have a range to print since start and end are known */
                int curr_page = start_page;
                gx_saved_pages_list_element *curr_elem = NULL;

                /* get the start_page saved_page */
                if (start_page <= list->count) {
                    for (curr_elem = list->head; curr_elem->sequence_number != start_page;
                                curr_elem = curr_elem->next) {
                        if (curr_elem->next == NULL) {
                             emprintf1(pdev->memory, "gx_saved_pages_list_print: page %d not found.\n", start_page);
                             code = gs_error_rangecheck;;
                             goto out;
                        }
                    }
                }

                for ( ; curr_elem != NULL; ) {

                    /* print the saved page from the current curr_elem */

                    if ((code = gx_output_saved_page(pdev, curr_elem->page)) < 0)
                        goto out;

                    curr_page += page_skip;
                    if (page_skip >= 0) {
                        if (curr_page > end_page)
                            break;
                        curr_elem = curr_elem->next;
                        if (page_skip > 1)
                            curr_elem = curr_elem->next;
                    } else {
                        /* reverse print order */
                        if (curr_page < end_page)
                            break;
                        curr_elem = curr_elem->prev;
                        /* Below is not needed since we never print reverse even/odd */
                        if (page_skip < -1)
                            curr_elem = curr_elem->prev;
                    }
                    if (curr_elem == NULL) {
                         emprintf1(pdev->memory, "gx_saved_pages_list_print: page %d not found.\n", curr_page);
                         code = gs_error_rangecheck;;
                         goto out;
                    }
                }

                /* If we were printing EVEN, we may need to spit out a blank 'pad' page */
                if (do_blank_page_pad) {
                    /* print the empty page we had upon entry */
                    /* FIXME: Note that the page size may not match the last odd page */
                    if ((code = gx_output_saved_page(pdev, &saved_page)) < 0)
                        goto out;
                }

                /* After printing, reset to handle next page range */
                start_page = (start_page == end_page) ? page : 0;   /* if single page, set start_page */
                                                                    /* from the number scanned above  */
                end_page = 0;
            }
            if (token_size == 0)
                break;				/* finished with print ranges */

            /* Move to next token */
            param_left -= token - param_scan + token_size;
            param_scan = token + token_size;
        }
    }
out:
    /* restore the device parameters saved upon entry */
    *printed_count = pdev->PageCount - list->PageCount;
    list->PageCount = pdev->PageCount;		/* retain for subsequent print action */
    pdev->saved_pages_list = list;
    pdev->bg_print_requested = save_bg_print;
    crdev->do_not_open_or_close_bandfiles = save_bandfile_open_close;

    /* load must be after we've set saved_pages_list which forces clist mode. */
    do_page_load(pdev, &saved_page, saved_files);

    /* Finally, do the finish page which will reset the clist to empty and write mode */
    endcode = clist_finish_page((gx_device *)pdev, true);
    return code < 0 ? code : endcode < 0 ? endcode : param_scan - param;
}