/* * Open the output seekable, because libtiff doesn't support writing to * non-positionable streams. Otherwise, these are the same as * gdev_prn_output_page() and gdev_prn_open(). */ int tiff_output_page(gx_device *pdev, int num_copies, int flush) { gx_device_printer * const ppdev = (gx_device_printer *)pdev; int outcode = 0, closecode = 0, errcode = 0, endcode; bool upgraded_copypage = false; if (num_copies > 0 || !flush) { int code = gdev_prn_open_printer_positionable(pdev, 1, 1); if (code < 0) return code; /* If copypage request, try to do it using buffer_page */ if ( !flush && (*ppdev->printer_procs.buffer_page) (ppdev, ppdev->file, num_copies) >= 0 ) { upgraded_copypage = true; flush = true; } else if (num_copies > 0) /* Print the accumulated page description. */ outcode = (*ppdev->printer_procs.print_page_copies)(ppdev, ppdev->file, num_copies); fflush(ppdev->file); errcode = (ferror(ppdev->file) ? gs_note_error(gs_error_ioerror) : 0); if (!upgraded_copypage) closecode = gdev_prn_close_printer(pdev); } endcode = (ppdev->buffer_space && !ppdev->is_async_renderer ? clist_finish_page(pdev, flush) : 0); if (outcode < 0) return outcode; if (errcode < 0) return errcode; if (closecode < 0) return closecode; if (endcode < 0) return endcode; endcode = gx_finish_output_page(pdev, num_copies, flush); return (endcode < 0 ? endcode : upgraded_copypage ? 1 : 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; }