0

Print Preview: Add option to rasterize PDFs and add JPEG compression.

Add checkbox to print preview to select rasterized PDF output. When
selected, PDF will be rasterized and printed as a series of images.
Images will be JPEG encoded.

Preliminary design doc: https://docs.google.com/a/google.com/document/d/1UTzurMuPeRgx2PcnTMuAq5iM5_R2QBNGp-9lzgtwT2k/edit?usp=sharing

Depends on http://crrev.com/2529543003

Linked to launch bug, should also resolve 534945,550205,480628

BUG=675798
CQ_INCLUDE_TRYBOTS=master.tryserver.chromium.linux:closure_compilation

Review-Url: https://codereview.chromium.org/2524143003
Cr-Commit-Position: refs/heads/master@{#440897}
This commit is contained in:
rbpotter
2016-12-28 14:00:23 -08:00
committed by Commit bot
parent a9a035ecfd
commit 0fab356029
31 changed files with 287 additions and 51 deletions

@ -5155,7 +5155,13 @@ Keep your key file in a safe place. You will need it to create new versions of y
"No-State Prefetch" pre-downloads resources to improve load times. "Prerender" does a full pre-rendering of the page, to improve load times even more. "Simple Load" does nothing and is similar to disabling the feature, but collects more metrics for comparison purposes.
</message>
<!-- Print scaling feature -->
<!-- Print Preview features -->
<message name="IDS_FLAGS_PRINT_PDF_AS_IMAGE_NAME" desc="Name for the flag to add the option to print PDFs as images to print preview.">
Print Pdf as Image
</message>
<message name="IDS_FLAGS_PRINT_PDF_AS_IMAGE_DESCRIPTION" desc="Description for the flag to add the option to print PDFs as images in print preview.">
If enabled, an option to print PDF files as images will be available in print preview.
</message>
<message name="IDS_FLAGS_PRINT_SCALING_NAME" desc="Name for the flag to add the print scaling feature to print preview.">
Print Scaling.
</message>
@ -8639,6 +8645,9 @@ I don't think this site should be blocked!
<message name="IDS_PRINT_PREVIEW_OPTION_SELECTION_ONLY" desc="Checkbox label shown in print preview page to print only selected content.">
Selection only
</message>
<message name="IDS_PRINT_PREVIEW_OPTION_RASTERIZE" desc="Checkbox label shown in print preview page to print PDF as an image (rasterize PDF).">
Print as image
</message>
<message name="IDS_PRINT_PREVIEW_MARGINS_LABEL" desc="Margins option label. Provides user the option to change the margins of the printed page.">
Margins
</message>

@ -2074,6 +2074,9 @@ const FeatureEntry kFeatureEntries[] = {
features::kDisplayPersistenceToggleInPermissionPrompts)},
#endif
#if BUILDFLAG(ENABLE_PRINT_PREVIEW)
{"print-pdf-as-image", IDS_FLAGS_PRINT_PDF_AS_IMAGE_NAME,
IDS_FLAGS_PRINT_PDF_AS_IMAGE_DESCRIPTION, kOsDesktop,
FEATURE_VALUE_TYPE(features::kPrintPdfAsImage)},
{"print-scaling", IDS_FLAGS_PRINT_SCALING_NAME,
IDS_FLAGS_PRINT_SCALING_DESCRIPTION, kOsDesktop,
FEATURE_VALUE_TYPE(features::kPrintScaling)},

@ -109,6 +109,14 @@ cr.define('print_preview', function() {
this.pageRange_ =
new print_preview.ticket_items.PageRange(this.documentInfo_);
/**
* Rasterize PDF ticket item.
* @type {!print_preview.ticket_items.Rasterize}
* @private
*/
this.rasterize_ = new print_preview.ticket_items.Rasterize(
this.destinationStore_, this.documentInfo_);
/**
* Scaling ticket item.
* @type {!print_preview.ticket_items.Scaling}
@ -291,6 +299,10 @@ cr.define('print_preview', function() {
return this.pageRange_;
},
get rasterize() {
return this.rasterize_;
},
get scaling() {
return this.scaling_;
},

@ -0,0 +1,50 @@
// Copyright (c) 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
cr.define('print_preview.ticket_items', function() {
'use strict';
/**
* Rasterize ticket item whose value is a {@code boolean} that indicates
* whether the PDF document should be rendered as images.
* @constructor
* @param {!print_preview.DocumentInfo} documentInfo Information about the
* document to print, used to determine if document is a PDF.
* @extends {print_preview.ticket_items.TicketItem}
*/
function Rasterize(destinationStore, documentInfo) {
print_preview.ticket_items.TicketItem.call(
this, null /* appState */, null /* field */,
null /* destinationStore */, documentInfo);
};
Rasterize.prototype = {
__proto__: print_preview.ticket_items.TicketItem.prototype,
/** @override */
wouldValueBeValid: function(value) {
return true;
},
/** @override */
isCapabilityAvailable: function() {
return !this.getDocumentInfoInternal().isModifiable;
},
/** @override */
getDefaultValueInternal: function() {
return false;
},
/** @override */
getCapabilityNotAvailableValueInternal: function() {
return this.getDefaultValueInternal();
}
};
// Export
return {
Rasterize: Rasterize
};
});

@ -288,6 +288,7 @@ cr.define('print_preview', function() {
'generateDraftData': documentInfo.isModifiable,
'fitToPageEnabled': printTicketStore.fitToPage.getValue(),
'scaleFactor': printTicketStore.scaling.getValueAsNumber(),
'rasterizePDF': printTicketStore.rasterize.getValue(),
// NOTE: Even though the following fields don't directly relate to the
// preview, they still need to be included.
'duplex': printTicketStore.duplex.getValue() ?
@ -367,6 +368,7 @@ cr.define('print_preview', function() {
'printWithCloudPrint': !destination.isLocal,
'printWithPrivet': destination.isPrivet,
'printWithExtension': destination.isExtension,
'rasterizePDF': printTicketStore.rasterize.getValue(),
'scaleFactor': printTicketStore.scaling.getValueAsNumber(),
'deviceName': destination.id,
'isFirstRequest': false,

@ -85,6 +85,13 @@ cr.define('print_preview', function() {
*/
this.colorValue_ = false;
/**
* Whether the document should be printed as a raster PDF.
* @type {boolean}
* @private
*/
this.rasterizeValue_ = false;
/**
* Whether the document should be fitted to the page.
* @type {boolean}
@ -184,6 +191,7 @@ cr.define('print_preview', function() {
this.isHeaderFooterEnabled_ =
this.printTicketStore_.headerFooter.getValue();
this.colorValue_ = this.printTicketStore_.color.getValue();
this.rasterizeValue_ = this.printTicketStore_.rasterize.getValue();
this.isFitToPageEnabled_ = this.printTicketStore_.fitToPage.getValue();
this.scalingValue_ = this.printTicketStore_.scaling.getValueAsNumber();
this.pageRanges_ = this.printTicketStore_.pageRange.getPageRanges();
@ -284,6 +292,7 @@ cr.define('print_preview', function() {
!ticketStore.landscape.isValueEqual(this.isLandscapeEnabled_) ||
!ticketStore.headerFooter.isValueEqual(this.isHeaderFooterEnabled_) ||
!ticketStore.color.isValueEqual(this.colorValue_) ||
!ticketStore.rasterize.isValueEqual(this.rasterizeValue_) ||
!ticketStore.scaling.isValueEqual(this.scalingValue_) ||
!ticketStore.fitToPage.isValueEqual(this.isFitToPageEnabled_) ||
this.pageRanges_ == null ||

@ -337,6 +337,7 @@ cr.define('print_preview', function() {
this.printTicketStore_.landscape,
this.printTicketStore_.marginsType,
this.printTicketStore_.pageRange,
this.printTicketStore_.rasterize,
this.printTicketStore_.selectionOnly,
this.printTicketStore_.scaling
].forEach(function(setting) {

@ -188,7 +188,8 @@ cr.define('print_preview', function() {
this.printTicketStore_.fitToPage,
this.printTicketStore_.cssBackground,
this.printTicketStore_.selectionOnly,
this.printTicketStore_.headerFooter);
this.printTicketStore_.headerFooter,
this.printTicketStore_.rasterize);
this.addChild(this.otherOptionsSettings_);
/**
@ -1322,6 +1323,7 @@ cr.define('print_preview', function() {
<include src="data/ticket_items/fit_to_page.js">
<include src="data/ticket_items/css_background.js">
<include src="data/ticket_items/selection_only.js">
<include src="data/ticket_items/rasterize.js">
<include src="data/ticket_items/vendor_items.js">
<include src="native_layer.js">

@ -29,6 +29,12 @@
<span>$i18n{optionBackgroundColorsAndImages}</span>
</label>
</div>
<div id="rasterize-container">
<label aria-live="polite">
<input class="checkbox" type="checkbox">
<span>$i18n{optionRasterize}</span>
</label>
</div>
<div id="selection-only-container">
<label aria-live="polite">
<input class="checkbox" type="checkbox">

@ -127,30 +127,42 @@ cr.define('print_preview', function() {
* only ticket item.
* @param {!print_preview.ticket_items.HeaderFooter} headerFooter Header
* footer ticket item.
* @param {!print_preview.ticket_items.Rasterize} rasterize Rasterize ticket
* item.
* @constructor
* @extends {print_preview.SettingsSection}
*/
function OtherOptionsSettings(
duplex, fitToPage, cssBackground, selectionOnly, headerFooter) {
duplex, fitToPage, cssBackground, selectionOnly, headerFooter,
rasterize) {
print_preview.SettingsSection.call(this);
/**
* @private {boolean} rasterizeEnabled Whether the print as image feature is
* enabled.
*/
this.rasterizeEnabled_ = loadTimeData.getBoolean('printPdfAsImageEnabled');
/*
/**
* @private {!Array<!CheckboxTicketItemElement>} checkbox ticket item
* elements representing the different options in the section.
* Selection only must always be the last element in the array.
*/
this.elements_ = [
new CheckboxTicketItemElement(headerFooter, true,
'header-footer-container'),
new CheckboxTicketItemElement(fitToPage, false,
'fit-to-page-container'),
new CheckboxTicketItemElement(duplex, false, 'duplex-container'),
new CheckboxTicketItemElement(cssBackground, true,
'css-background-container'),
new CheckboxTicketItemElement(selectionOnly, true,
'selection-only-container')
new CheckboxTicketItemElement(headerFooter, true,
'header-footer-container'),
new CheckboxTicketItemElement(fitToPage, false,
'fit-to-page-container'),
new CheckboxTicketItemElement(duplex, false, 'duplex-container'),
new CheckboxTicketItemElement(cssBackground, true,
'css-background-container'),
new CheckboxTicketItemElement(selectionOnly, true,
'selection-only-container')
];
if (this.rasterizeEnabled_) {
this.elements_.splice(4, 0,
new CheckboxTicketItemElement(rasterize, true,
'rasterize-container'));
}
};
OtherOptionsSettings.prototype = {
@ -206,6 +218,7 @@ cr.define('print_preview', function() {
decorateInternal: function() {
for (var i = 0; i < this.elements_.length; i++)
this.elements_[i].decorate();
$('rasterize-container').hidden = !this.rasterizeEnabled_;
},
/** @override */

@ -142,6 +142,7 @@ enum PrintSettingsBuckets {
NON_DEFAULT_MARGINS,
DISTILL_PAGE_UNUSED,
SCALING,
PRINT_AS_IMAGE,
PRINT_SETTINGS_BUCKET_BOUNDARY
};
@ -289,6 +290,12 @@ void ReportPrintSettingsStats(const base::DictionaryValue& settings) {
&external_preview) && external_preview) {
ReportPrintSettingHistogram(EXTERNAL_PDF_PREVIEW);
}
bool rasterize = false;
if (settings.GetBoolean(printing::kSettingRasterizePdf,
&rasterize) && rasterize) {
ReportPrintSettingHistogram(PRINT_AS_IMAGE);
}
}
// Callback that stores a PDF file on disk.

@ -278,6 +278,8 @@ content::WebUIDataSource* CreatePrintPreviewUISource() {
IDS_PRINT_PREVIEW_OPTION_BACKGROUND_COLORS_AND_IMAGES);
source->AddLocalizedString("optionSelectionOnly",
IDS_PRINT_PREVIEW_OPTION_SELECTION_ONLY);
source->AddLocalizedString("optionRasterize",
IDS_PRINT_PREVIEW_OPTION_RASTERIZE);
source->AddLocalizedString("marginsLabel", IDS_PRINT_PREVIEW_MARGINS_LABEL);
source->AddLocalizedString("defaultMargins",
IDS_PRINT_PREVIEW_DEFAULT_MARGINS);
@ -410,6 +412,10 @@ content::WebUIDataSource* CreatePrintPreviewUISource() {
bool scaling_enabled = base::FeatureList::IsEnabled(features::kPrintScaling);
source->AddBoolean("scalingEnabled", scaling_enabled);
bool print_pdf_as_image_enabled = base::FeatureList::IsEnabled(
features::kPrintPdfAsImage);
source->AddBoolean("printPdfAsImageEnabled", print_pdf_as_image_enabled);
#if defined(OS_CHROMEOS)
bool cups_and_md_settings_enabled =
base::CommandLine::ForCurrentProcess()->HasSwitch(

@ -169,6 +169,9 @@ const base::Feature kPreferHtmlOverPlugins{"PreferHtmlOverPlugins",
// Enables the Print Scaling feature in print preview.
#if BUILDFLAG(ENABLE_PRINT_PREVIEW)
const base::Feature kPrintPdfAsImage{"PrintPdfAsImage",
base::FEATURE_DISABLED_BY_DEFAULT};
const base::Feature kPrintScaling{"PrintScaling",
base::FEATURE_DISABLED_BY_DEFAULT};
#endif

@ -100,6 +100,8 @@ extern const base::Feature kPreferHtmlOverPlugins;
#endif
#if BUILDFLAG(ENABLE_PRINT_PREVIEW)
extern const base::Feature kPrintPdfAsImage;
extern const base::Feature kPrintScaling;
#endif

@ -61,12 +61,16 @@ PrintPreviewWebUITest.prototype = {
* @override
*/
testGenPreamble: function() {
// Enable print scaling for tests.
// Enable print scaling and print as image for tests.
GEN(' base::FeatureList::ClearInstanceForTesting();');
GEN(' std::unique_ptr<base::FeatureList>');
GEN(' feature_list(new base::FeatureList);');
GEN(' char enabled_features[128] = {0};');
GEN(' strcpy(enabled_features, features::kPrintScaling.name);');
GEN(' strcat(strcat(enabled_features, ","), ');
GEN(' features::kPrintPdfAsImage.name);');
GEN(' feature_list->InitializeFromCommandLine(');
GEN(' features::kPrintScaling.name, std::string());');
GEN(' enabled_features, std::string());');
GEN(' base::FeatureList::SetInstance(std::move(feature_list));');
},
@ -519,7 +523,11 @@ TEST_F('PrintPreviewWebUITest', 'PrintToPDFSelectedCapabilities', function() {
this.setCapabilities(device);
var otherOptions = $('other-options-settings');
checkSectionVisible(otherOptions, false);
checkSectionVisible(otherOptions, true);
checkElementDisplayed(
otherOptions.querySelector('#fit-to-page-container'), false);
checkElementDisplayed(
otherOptions.querySelector('#rasterize-container'), true);
checkSectionVisible($('media-size-settings'), false);
checkSectionVisible($('scaling-settings'), false);
@ -535,6 +543,7 @@ TEST_F('PrintPreviewWebUITest', 'SourceIsHTMLCapabilities', function() {
var otherOptions = $('other-options-settings');
var fitToPage = otherOptions.querySelector('#fit-to-page-container');
var rasterize = otherOptions.querySelector('#rasterize-container');
var mediaSize = $('media-size-settings');
var scalingSettings = $('scaling-settings');
@ -542,12 +551,14 @@ TEST_F('PrintPreviewWebUITest', 'SourceIsHTMLCapabilities', function() {
// available).
checkSectionVisible(otherOptions, true);
checkElementDisplayed(fitToPage, false);
checkElementDisplayed(rasterize, false);
checkSectionVisible(mediaSize, false);
checkSectionVisible(scalingSettings, false);
this.expandMoreSettings();
checkElementDisplayed(fitToPage, false);
checkElementDisplayed(rasterize, false);
checkSectionVisible(mediaSize, true);
checkSectionVisible(scalingSettings, true);
@ -566,12 +577,18 @@ TEST_F('PrintPreviewWebUITest', 'SourceIsPDFCapabilities', function() {
var scalingSettings = $('scaling-settings');
var fitToPageContainer =
otherOptions.querySelector('#fit-to-page-container');
var rasterizeContainer =
otherOptions.querySelector('#rasterize-container');
checkSectionVisible(otherOptions, true);
checkElementDisplayed(fitToPageContainer, true);
checkElementDisplayed(rasterizeContainer, false);
expectTrue(
fitToPageContainer.querySelector('.checkbox').checked);
this.expandMoreSettings();
checkElementDisplayed(rasterizeContainer, true);
expectFalse(
rasterizeContainer.querySelector('.checkbox').checked);
checkSectionVisible($('media-size-settings'), true);
checkSectionVisible(scalingSettings, true);

@ -25,6 +25,7 @@ void RenderParamsFromPrintSettings(const PrintSettings& settings,
params->scale_factor = settings.scale_factor();
// Currently hardcoded at 72dpi. See PrintSettings' constructor.
params->desired_dpi = settings.desired_dpi();
params->rasterize_pdf = settings.rasterize_pdf();
// Always use an invalid cookie.
params->document_cookie = 0;
params->selection_only = settings.selection_only();

@ -42,26 +42,27 @@ namespace IPC {
} // namespace IPC
PrintMsg_Print_Params::PrintMsg_Print_Params()
: page_size(),
content_size(),
printable_area(),
margin_top(0),
margin_left(0),
dpi(0),
scale_factor(1.0f),
desired_dpi(0),
document_cookie(0),
selection_only(false),
supports_alpha_blend(false),
preview_ui_id(-1),
preview_request_id(0),
is_first_request(false),
print_scaling_option(blink::WebPrintScalingOptionSourceSize),
print_to_pdf(false),
display_header_footer(false),
title(),
url(),
should_print_backgrounds(false) {}
: page_size(),
content_size(),
printable_area(),
margin_top(0),
margin_left(0),
dpi(0),
scale_factor(1.0f),
desired_dpi(0),
rasterize_pdf(false),
document_cookie(0),
selection_only(false),
supports_alpha_blend(false),
preview_ui_id(-1),
preview_request_id(0),
is_first_request(false),
print_scaling_option(blink::WebPrintScalingOptionSourceSize),
print_to_pdf(false),
display_header_footer(false),
title(),
url(),
should_print_backgrounds(false) {}
PrintMsg_Print_Params::PrintMsg_Print_Params(
const PrintMsg_Print_Params& other) = default;
@ -77,6 +78,7 @@ void PrintMsg_Print_Params::Reset() {
dpi = 0;
scale_factor = 1.0f;
desired_dpi = 0;
rasterize_pdf = false;
document_cookie = 0;
selection_only = false;
supports_alpha_blend = false;

@ -47,6 +47,7 @@ struct PrintMsg_Print_Params {
double dpi;
double scale_factor;
int desired_dpi;
bool rasterize_pdf;
int document_cookie;
bool selection_only;
bool supports_alpha_blend;
@ -128,6 +129,9 @@ IPC_STRUCT_TRAITS_BEGIN(PrintMsg_Print_Params)
// Desired apparent dpi on paper.
IPC_STRUCT_TRAITS_MEMBER(desired_dpi)
// Whether to rasterize a PDF for printing
IPC_STRUCT_TRAITS_MEMBER(rasterize_pdf)
// Cookie for the document to ensure correctness.
IPC_STRUCT_TRAITS_MEMBER(document_cookie)

@ -286,6 +286,7 @@ void ComputeWebKitPrintParamsInDesiredDpi(
blink::WebPrintParams* webkit_print_params) {
int dpi = GetDPI(&print_params);
webkit_print_params->printerDPI = dpi;
webkit_print_params->rasterizePDF = print_params.rasterize_pdf;
webkit_print_params->printScalingOption = print_params.print_scaling_option;
webkit_print_params->printContentArea.width = ConvertUnit(

@ -1765,23 +1765,31 @@ void PepperPluginInstanceImpl::ReportGeometry() {
}
bool PepperPluginInstanceImpl::GetPreferredPrintOutputFormat(
PP_PrintOutputFormat_Dev* format) {
PP_PrintOutputFormat_Dev* format,
const WebPrintParams& print_params) {
// Keep a reference on the stack. See NOTE above.
scoped_refptr<PepperPluginInstanceImpl> ref(this);
if (!LoadPrintInterface())
return false;
uint32_t supported_formats =
plugin_print_interface_->QuerySupportedFormats(pp_instance());
if (supported_formats & PP_PRINTOUTPUTFORMAT_PDF) {
if ((supported_formats & PP_PRINTOUTPUTFORMAT_PDF) &&
!print_params.rasterizePDF) {
*format = PP_PRINTOUTPUTFORMAT_PDF;
return true;
}
if (supported_formats & PP_PRINTOUTPUTFORMAT_RASTER) {
*format = PP_PRINTOUTPUTFORMAT_RASTER;
return true;
}
return false;
}
bool PepperPluginInstanceImpl::SupportsPrintInterface() {
PP_PrintOutputFormat_Dev format;
return GetPreferredPrintOutputFormat(&format);
WebPrintParams params;
params.rasterizePDF = false;
return GetPreferredPrintOutputFormat(&format, params);
}
bool PepperPluginInstanceImpl::IsPrintScalingDisabled() {
@ -1795,7 +1803,7 @@ int PepperPluginInstanceImpl::PrintBegin(const WebPrintParams& print_params) {
// Keep a reference on the stack. See NOTE above.
scoped_refptr<PepperPluginInstanceImpl> ref(this);
PP_PrintOutputFormat_Dev format;
if (!GetPreferredPrintOutputFormat(&format)) {
if (!GetPreferredPrintOutputFormat(&format, print_params)) {
// PrintBegin should not have been called since SupportsPrintInterface
// would have returned false;
NOTREACHED();
@ -1857,7 +1865,8 @@ void PepperPluginInstanceImpl::PrintPageHelper(
if (!print_output)
return;
if (current_print_settings_.format == PP_PRINTOUTPUTFORMAT_PDF)
if (current_print_settings_.format == PP_PRINTOUTPUTFORMAT_PDF ||
current_print_settings_.format == PP_PRINTOUTPUTFORMAT_RASTER)
PrintPDFOutput(print_output, metafile);
// Now we need to release the print output resource.

@ -647,7 +647,8 @@ class CONTENT_EXPORT PepperPluginInstanceImpl
// Queries the plugin for supported print formats and sets |format| to the
// best format to use. Returns false if the plugin does not support any
// print format that we can handle (we can handle only PDF).
bool GetPreferredPrintOutputFormat(PP_PrintOutputFormat_Dev* format);
bool GetPreferredPrintOutputFormat(PP_PrintOutputFormat_Dev* format,
const blink::WebPrintParams& params);
bool PrintPDFOutput(PP_Resource print_output,
printing::PdfMetafileSkia* metafile);

@ -5,4 +5,5 @@ include_rules = [
"+printing/units.h",
"+third_party/pdfium/public",
"+ui/gfx/geometry/rect.h",
"+ui/gfx/codec/jpeg_codec.h",
]

@ -57,6 +57,7 @@
#include "third_party/pdfium/public/fpdf_transformpage.h"
#include "third_party/pdfium/public/fpdfview.h"
#include "ui/events/keycodes/keyboard_codes.h"
#include "ui/gfx/codec/jpeg_codec.h"
#include "ui/gfx/geometry/rect.h"
#include "v8/include/v8.h"
@ -617,6 +618,17 @@ void TearDownV8() {
g_isolate_holder = nullptr;
}
int GetBlockForJpeg(void* param,
unsigned long pos,
unsigned char* buf,
unsigned long size) {
std::vector<uint8_t>* data_vector = static_cast<std::vector<uint8_t>*>(param);
if (pos + size < pos || pos + size > data_vector->size())
return 0;
memcpy(buf, data_vector->data() + pos, size);
return 1;
}
} // namespace
bool InitializeSDK() {
@ -1353,9 +1365,11 @@ bool PDFiumEngine::HandleEvent(const pp::InputEvent& event) {
}
uint32_t PDFiumEngine::QuerySupportedPrintOutputFormats() {
if (!HasPermission(PDFEngine::PERMISSION_PRINT_LOW_QUALITY))
return 0;
return PP_PRINTOUTPUTFORMAT_PDF;
if (HasPermission(PDFEngine::PERMISSION_PRINT_HIGH_QUALITY))
return PP_PRINTOUTPUTFORMAT_PDF | PP_PRINTOUTPUTFORMAT_RASTER;
if (HasPermission(PDFEngine::PERMISSION_PRINT_LOW_QUALITY))
return PP_PRINTOUTPUTFORMAT_RASTER;
return 0;
}
void PDFiumEngine::PrintBegin() {
@ -1366,10 +1380,13 @@ pp::Resource PDFiumEngine::PrintPages(
const PP_PrintPageNumberRange_Dev* page_ranges, uint32_t page_range_count,
const PP_PrintSettings_Dev& print_settings) {
ScopedSubstFont scoped_subst_font(this);
if (HasPermission(PDFEngine::PERMISSION_PRINT_HIGH_QUALITY))
if (HasPermission(PDFEngine::PERMISSION_PRINT_HIGH_QUALITY) &&
(print_settings.format & PP_PRINTOUTPUTFORMAT_PDF)) {
return PrintPagesAsPDF(page_ranges, page_range_count, print_settings);
else if (HasPermission(PDFEngine::PERMISSION_PRINT_LOW_QUALITY))
} else if (HasPermission(PDFEngine::PERMISSION_PRINT_LOW_QUALITY)) {
return PrintPagesAsRasterPDF(page_ranges, page_range_count, print_settings);
}
return pp::Resource();
}
@ -1412,6 +1429,8 @@ FPDF_DOCUMENT PDFiumEngine::CreateSinglePageRasterPdf(
print_settings.orientation,
FPDF_ANNOT | FPDF_PRINTING | FPDF_NO_CATCH);
unsigned char* bitmap_data =
static_cast<unsigned char*>(FPDFBitmap_GetBuffer(bitmap));
double ratio_x = ConvertUnitDouble(bitmap_size.width(),
print_settings.dpi,
kPointsPerInch);
@ -1422,7 +1441,25 @@ FPDF_DOCUMENT PDFiumEngine::CreateSinglePageRasterPdf(
// Add the bitmap to an image object and add the image object to the output
// page.
FPDF_PAGEOBJECT temp_img = FPDFPageObj_NewImgeObj(temp_doc);
FPDFImageObj_SetBitmap(&temp_page, 1, temp_img, bitmap);
std::vector<uint8_t> compressed_bitmap_data;
int quality = 40;
if (!(print_settings.format & PP_PRINTOUTPUTFORMAT_PDF) &&
(gfx::JPEGCodec::Encode(
bitmap_data, gfx::JPEGCodec::FORMAT_BGRA, FPDFBitmap_GetWidth(bitmap),
FPDFBitmap_GetHeight(bitmap), FPDFBitmap_GetStride(bitmap), quality,
&compressed_bitmap_data))) {
FPDF_FILEACCESS file_access = {};
file_access.m_FileLen =
static_cast<unsigned long>(compressed_bitmap_data.size());
file_access.m_GetBlock = &GetBlockForJpeg;
file_access.m_Param = &compressed_bitmap_data;
FPDFImageObj_LoadJpegFileInline(&temp_page, 1, temp_img, &file_access);
} else {
FPDFImageObj_SetBitmap(&temp_page, 1, temp_img, bitmap);
}
FPDFImageObj_SetMatrix(temp_img, ratio_x, 0, 0, ratio_y, 0, 0);
FPDFPage_InsertObject(temp_page, temp_img);
FPDFPage_GenerateContent(temp_page);

@ -172,6 +172,9 @@ const char kSettingPrintWithExtension[] = "printWithExtension";
// Scaling factor
const char kSettingScaleFactor[] = "scaleFactor";
// Scaling factor
const char kSettingRasterizePdf[] = "rasterizePDF";
// Ticket option. Contains the ticket in CJT format.
const char kSettingTicket[] = "ticket";

@ -65,6 +65,7 @@ PRINTING_EXPORT extern const char kSettingPrintableAreaY[];
PRINTING_EXPORT extern const char kSettingPrinterDescription[];
PRINTING_EXPORT extern const char kSettingPrinterName[];
PRINTING_EXPORT extern const char kSettingPrinterOptions[];
PRINTING_EXPORT extern const char kSettingRasterizePdf[];
PRINTING_EXPORT extern const char kSettingScaleFactor[];
PRINTING_EXPORT extern const char kSettingTicket[];
PRINTING_EXPORT extern const char kSettingShouldPrintBackgrounds[];

@ -96,6 +96,9 @@ class PRINTING_EXPORT PrintSettings {
void set_scale_factor(double scale_factor) { scale_factor_ = scale_factor; }
double scale_factor() const { return scale_factor_; }
void set_rasterize_pdf(bool rasterize_pdf) { rasterize_pdf_ = rasterize_pdf; }
bool rasterize_pdf() const { return rasterize_pdf_; }
void set_supports_alpha_blend(bool supports_alpha_blend) {
supports_alpha_blend_ = supports_alpha_blend;
}
@ -212,6 +215,9 @@ class PRINTING_EXPORT PrintSettings {
// Scale factor
double scale_factor_;
// True if PDF should be printed as a raster PDF
bool rasterize_pdf_;
// Is the orientation landscape or portrait.
bool landscape_;

@ -177,6 +177,7 @@ bool PrintSettingsFromJobSettings(const base::DictionaryValue& job_settings,
bool collate = false;
int copies = 1;
int scale_factor = 100;
bool rasterize_pdf = false;
if (!job_settings.GetBoolean(kSettingCollate, &collate) ||
!job_settings.GetInteger(kSettingCopies, &copies) ||
@ -184,7 +185,8 @@ bool PrintSettingsFromJobSettings(const base::DictionaryValue& job_settings,
!job_settings.GetInteger(kSettingDuplexMode, &duplex_mode) ||
!job_settings.GetBoolean(kSettingLandscape, &landscape) ||
!job_settings.GetString(kSettingDeviceName, &device_name) ||
!job_settings.GetInteger(kSettingScaleFactor, &scale_factor)) {
!job_settings.GetInteger(kSettingScaleFactor, &scale_factor) ||
!job_settings.GetBoolean(kSettingRasterizePdf, &rasterize_pdf)) {
return false;
}
@ -195,7 +197,7 @@ bool PrintSettingsFromJobSettings(const base::DictionaryValue& job_settings,
settings->set_duplex_mode(static_cast<DuplexMode>(duplex_mode));
settings->set_color(static_cast<ColorModel>(color));
settings->set_scale_factor(static_cast<double>(scale_factor) / 100.0);
settings->set_rasterize_pdf(rasterize_pdf);
#if defined(OS_WIN)
// Modifiable implies HTML and not other formats like PDF.
bool can_modify = false;

@ -73,6 +73,7 @@ PrintingContext::Result PrintingContext::UsePdfSettings() {
pdf_settings->SetBoolean(kSettingPrintWithPrivet, false);
pdf_settings->SetBoolean(kSettingPrintWithExtension, false);
pdf_settings->SetInteger(kSettingScaleFactor, 100);
pdf_settings->SetBoolean(kSettingRasterizePdf, false);
return UpdatePrintSettings(*pdf_settings);
}

@ -1595,6 +1595,24 @@
]
}
],
"PrintPdfAsImage": [
{
"platforms": [
"chromeos",
"linux",
"mac",
"win"
],
"experiments": [
{
"name": "Enabled",
"enable_features": [
"PrintPdfAsImage"
]
}
]
}
],
"PrintScaling": [
{
"platforms": [

@ -51,6 +51,9 @@ struct WebPrintParams {
// Specifies user selected DPI for printing.
int printerDPI;
// Specifies whether to print PDFs as image.
bool rasterizePDF = false;
// Specifies whether to reduce/enlarge/retain the print contents to fit the
// printable area. (This is used only by plugin printing).
WebPrintScalingOption printScalingOption;

@ -93987,6 +93987,7 @@ value.
<int value="147373243" label="enable-deferred-image-decoding"/>
<int value="157217034" label="enable-tab-for-desktop-share"/>
<int value="157318016" label="AutomaticTabDiscarding:enabled"/>
<int value="173288154" label="PrintPdfAsImage:enabled"/>
<int value="178337215" label="enable-md-history"/>
<int value="180074362" label="memory-pressure-thresholds"/>
<int value="189728101" label="FasterLocationReload:disabled"/>
@ -94078,9 +94079,11 @@ value.
<int value="606512202" label="AutofillCreditCardPopupLayout:enabled"/>
<int value="609112512" label="touch-selection-strategy"/>
<int value="610545308" label="enable-potentially-annoying-security-features"/>
<int value="624317932" label="print-pdf-as-image"/>
<int value="625273056" label="disable-boot-animation"/>
<int value="628302973" label="NTPSnippets:enabled"/>
<int value="630947363" label="touch-events"/>
<int value="635971109" label="PrintPdfAsImage:disabled"/>
<int value="636425179" label="mhtml-generator-option"/>
<int value="637396292" label="AllBookmarks:enabled"/>
<int value="643725031" label="disable-touch-feedback"/>
@ -100023,6 +100026,7 @@ value.
<int value="16" label="NON_DEFAULT_MARGINS"/>
<int value="17" label="DISTILL_PAGE_UNUSED"/>
<int value="18" label="SCALING"/>
<int value="19" label="PRINT_AS_IMAGE"/>
</enum>
<enum name="PrivetNotificationsEvent" type="int">