Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions cupsfilters/ipp-options-private.h
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,13 @@ typedef enum cf_filter_orient_s // "orientation-requested" values
CF_FILTER_ORIENT_NONE // No rotation
} cf_filter_orient_t;

typedef enum pdftopdf_booklet_mode_e
{
CF_PDFTOPDF_BOOKLET_OFF,
CF_PDFTOPDF_BOOKLET_ON,
CF_PDFTOPDF_BOOKLET_JUST_SHUFFLE
} pdftopdf_booklet_mode_t;

typedef enum cf_filter_error_report_e // Combination of "job-error-sheet-type" and "job-error-sheet-when" values
{
CF_FILTER_ERROR_REPORT_NONE, // "job-error-sheet-type" = 'none'
Expand Down Expand Up @@ -190,8 +197,10 @@ typedef struct cf_filter_options_s // All filter options in one structure
size_t num_force_front_side; // Number of "force-front-side" values
int force_front_side[100]; // "force-front-side" values
cf_filter_orient_t image_orientation; // "image-orientation" value
char imposition_template[128];
// "imposition-template" value, if any
pdftopdf_booklet_mode_t booklet;
// "booklet" or "imposition-template" value
int booklet_signature;
// "booklet-signature" value, in sheets; -1 means all pages
ippopt_error_sheet_t job_error_sheet; // "job-error-sheet" value
char job_name[256]; // "job-name" value
char job_originating_user_name[256];
Expand Down
29 changes: 20 additions & 9 deletions cupsfilters/ipp-options.c
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,8 @@ cfFilterOptionsCreate(size_t num_options, // I - Number of command-line option
return (NULL);

ippo->copies = 1;
ippo->booklet = CF_PDFTOPDF_BOOKLET_OFF;
ippo->booklet_signature = -1;
ippo->image_orientation = CF_FILTER_ORIENT_NONE;
ippo->multiple_document_handling = CF_FILTER_HANDLING_COLLATED_COPIES;
ippo->print_scaling = CF_FILTER_SCALING_AUTO;
Expand Down Expand Up @@ -493,16 +495,25 @@ cfFilterOptionsCreate(size_t num_options, // I - Number of command-line option
if ((value = get_option("imposition-template", num_options, options)) != NULL ||
(value = get_option("booklet", num_options, options)) != NULL)
{
if(!strcasecmp(value, "yes") ||
!strcasecmp(value, "true") ||
!strcasecmp(value, "booklet"))
{
cupsCopyString(ippo->imposition_template, "booklet", sizeof(ippo->imposition_template));
}
else
{
if (!strcasecmp(value, "shuffle-only"))
ippo->booklet = CF_PDFTOPDF_BOOKLET_JUST_SHUFFLE;
else if (!strcasecmp(value, "yes") ||
!strcasecmp(value, "true") ||
!strcasecmp(value, "booklet"))
ippo->booklet = CF_PDFTOPDF_BOOKLET_ON;
else if (strcasecmp(value, "no") &&
strcasecmp(value, "false") &&
strcasecmp(value, "none"))
fprintf(stderr, "cfFilterPDFToPDF: Unsupported booklet value %s, using booklet off", value);
}
}

if ((value = get_option("booklet-signature", num_options, options)) != NULL)
{
intvalue = atoi(value);
if (intvalue > 0)
ippo->booklet_signature = intvalue;
else
fprintf(stderr, "cfFilterPDFToPDF: Unsupported booklet-signature value %s, using all pages", value);
}

if ((value = get_option("job-error-sheet", num_options, options)) != NULL)
Expand Down
114 changes: 111 additions & 3 deletions cupsfilters/pdftopdf.c
Original file line number Diff line number Diff line change
Expand Up @@ -630,7 +630,7 @@ prepare_number_up(xform_prepare_t *p) // I - Preparation data
height; // Height of layout rectangle


if (!strcmp(p->options->imposition_template, "booklet"))
if (p->options->booklet == CF_PDFTOPDF_BOOKLET_ON)
{
// "imposition-template" = 'booklet' forces 2-up output...
p->num_layout = 2;
Expand Down Expand Up @@ -765,7 +765,115 @@ prepare_pages(
bool use_page; // Use this page?


if (!strcmp(p->options->imposition_template, "booklet"))
if (p->options->booklet == CF_PDFTOPDF_BOOKLET_JUST_SHUFFLE)
{
pdfio_obj_t *selected_pages[XFORM_MAX_PAGES] = {NULL};
size_t selected_page_count = 0;
size_t output_page_count;
size_t signature_size;

// First collect the selected pages in their normal document order.
for (page = 1, i = num_documents, d = documents; i > 0; i--, d++)
{
while (page <= d->last_page)
{
if ((p->options->multiple_document_handling < CF_FILTER_HANDLING_SINGLE_DOCUMENT &&
cfFilterOptionsIsPageInRange(p->options, page - d->first_page + 1)) ||
(p->options->multiple_document_handling >= CF_FILTER_HANDLING_SINGLE_DOCUMENT &&
cfFilterOptionsIsPageInRange(p->options, page)))
{
selected_pages[selected_page_count++] =
pdfioFileGetPage(d->pdf, (size_t)(page - d->first_page));
}
page++;
}

if (p->options->multiple_document_handling < CF_FILTER_HANDLING_SINGLE_DOCUMENT)
page = 1;
}

// A sheet has two sides, so each signature contains four pages per sheet.
signature_size = p->options->booklet_signature > 0 ?
(size_t)p->options->booklet_signature * 4 : selected_page_count;
if (signature_size < 4)
signature_size = 4;

// Add blank pages to complete the last signature.
output_page_count = (selected_page_count + signature_size - 1) /
signature_size * signature_size;
p->num_outpages = output_page_count;

// Each signature is ordered from the outside inward:
// last, first, second, penultimate, ...
for (current = 0; current < output_page_count; current++)
{
size_t signature_start = (current / signature_size) * signature_size;
size_t signature_slot = current % signature_size;
size_t source_page;
size_t pair = signature_slot / 2;

if ((signature_slot & 1) == 0)
source_page = signature_start + signature_size - 1 - pair;
else
source_page = signature_start + pair;

p->outpages[current].pdf = p->pdf;
if (source_page < selected_page_count)
p->outpages[current].input[0] = selected_pages[source_page];
}
}
else if (p->options->booklet == CF_PDFTOPDF_BOOKLET_ON &&
p->options->booklet_signature > 0)
{
pdfio_obj_t *selected_pages[XFORM_MAX_PAGES] = { NULL };
size_t selected_page_count = 0;
size_t signature_size = (size_t)p->options->booklet_signature * 4;
size_t shuffled_page_count;

// Collect the pages selected for printing.
for (page = 1, i = num_documents, d = documents; i > 0; i--, d++)
{
while (page <= d->last_page)
{
if ((p->options->multiple_document_handling < CF_FILTER_HANDLING_SINGLE_DOCUMENT &&
cfFilterOptionsIsPageInRange(p->options, page - d->first_page + 1)) ||
(p->options->multiple_document_handling >= CF_FILTER_HANDLING_SINGLE_DOCUMENT &&
cfFilterOptionsIsPageInRange(p->options, page)))
selected_pages[selected_page_count++] =
pdfioFileGetPage(d->pdf, (size_t)(page - d->first_page));

page++;
}

if (p->options->multiple_document_handling < CF_FILTER_HANDLING_SINGLE_DOCUMENT)
page = 1;
}

// Pad each signature to a complete set of sheets, then create 2-up pages.
shuffled_page_count = (selected_page_count + signature_size - 1) /
signature_size * signature_size;
p->num_outpages = shuffled_page_count / 2;

for (current = 0; current < shuffled_page_count; current ++)
{
size_t signature_start = (current / signature_size) * signature_size;
size_t signature_slot = current % signature_size;
size_t pair = signature_slot / 2;
size_t source_page;
size_t output_page = current / 2;
size_t output_slot = current % 2;

if ((signature_slot & 1) == 0)
source_page = signature_start + signature_size - 1 - pair;
else
source_page = signature_start + pair;

p->outpages[output_page].pdf = p->pdf;
if (source_page < selected_page_count)
p->outpages[output_page].input[output_slot] = selected_pages[source_page];
}
}
else if (p->options->booklet == CF_PDFTOPDF_BOOKLET_ON)
{
// Booklet printing arranges input pages so that the folded output can be
// stapled along the midline...
Expand All @@ -782,7 +890,7 @@ prepare_pages(
else
use_page = cfFilterOptionsIsPageInRange(p->options, page);

if (use_page)
if (use_page)
{
if (current < p->num_outpages)
outpage = p->outpages + current;
Expand Down
5 changes: 5 additions & 0 deletions cupsfilters/test-filter-cases.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ cupsfilters/test_files/test_file_4pg.pdf application/pdf cupsfilters/test_files/
cupsfilters/test_files/test_file_4pg.pdf application/pdf cupsfilters/test_files/output_files/output_landscape_true.pdf application/pdf Generic PDF Color 2 1 1 text/plain,application/pdf 13 new-user custom-print 10 media-size=A4 printer-resolution=300dpi landscape=true
cupsfilters/test_files/test_file_4pg.pdf application/pdf cupsfilters/test_files/output_files/output_nup_2.pdf application/pdf Generic PDF Color 2 1 1 text/plain,application/pdf 13 new-user custom-print 10 media-size=A4 printer-resolution=300dpi number-up=2
cupsfilters/test_files/test_file_4pg.pdf application/pdf cupsfilters/test_files/output_files/output_booklet.pdf application/pdf Generic PDF Color 2 1 1 text/plain,application/pdf 13 new-user custom-print 10 media-size=A4 printer-resolution=300dpi booklet=true sides=two-sided-short-edge
cupsfilters/test_files/test_file_4pg.pdf application/pdf cupsfilters/test_files/output_files/output_booklet_true.pdf application/pdf Generic PDF Color 2 1 1 text/plain,application/pdf 13 new-user custom-print 10 media-size=A4 printer-resolution=300dpi booklet=true sides=two-sided-short-edge
cupsfilters/test_files/test_file_4pg.pdf application/pdf cupsfilters/test_files/output_files/output_booklet_signature_1_2up.pdf application/pdf Generic PDF Color 2 1 1 text/plain,application/pdf 13 new-user custom-print 10 media-size=A4 printer-resolution=300dpi booklet=true booklet-signature=1 sides=two-sided-short-edge
cupsfilters/test_files/test_file_4pg.pdf application/pdf cupsfilters/test_files/output_files/output_booklet_shuffle_only.pdf application/pdf Generic PDF Color 2 1 1 text/plain,application/pdf 13 new-user custom-print 10 media-size=A4 printer-resolution=300dpi booklet=shuffle-only sides=two-sided-short-edge
cupsfilters/test_files/test_file_4pg.pdf application/pdf cupsfilters/test_files/output_files/output_booklet_signature_1.pdf application/pdf Generic PDF Color 2 1 1 text/plain,application/pdf 13 new-user custom-print 10 media-size=A4 printer-resolution=300dpi booklet=shuffle-only booklet-signature=1 sides=two-sided-short-edge
cupsfilters/test_files/test_file_4pg.pdf application/pdf cupsfilters/test_files/output_files/output_booklet_false.pdf application/pdf Generic PDF Color 2 1 1 text/plain,application/pdf 13 new-user custom-print 10 media-size=A4 printer-resolution=300dpi booklet=false sides=two-sided-short-edge
cupsfilters/test_files/test_file_4pg.pdf application/pdf cupsfilters/test_files/output_files/output_mirror.pdf application/pdf Generic PDF Color 2 1 1 text/plain,application/pdf 13 new-user custom-print 10 media-size=A4 printer-resolution=300dpi mirror=true
cupsfilters/test_files/test_file_4pg.pdf application/pdf cupsfilters/test_files/output_files/test_file_op.pwg image/pwg-raster Generic PDF Color 2 1 1 image/pwg-raster,application/pdf 13 new-user custom-print 5 sides=two-sided-short-edge media-size=A4 printer-resolution=300dpi
cupsfilters/test_files/test_file_4pg.pdf application/pdf cupsfilters/test_files/output_files/test_file_op.pwg image/pwg-raster Generic PDF Color 2 1 1 image/pwg-raster,application/pdf 13 new-user custom-print 5 sides=two-sided-short-edge media-size=A4 printer-resolution=300dpi
Expand Down
Loading