Merge pull request #9593 from Snuffleupagus/pageSize-orientation

Improve the pageSize entry in the document properties dialog, by also displaying page names and orientation
This commit is contained in:
Tim van der Meij 2018-03-25 21:52:11 +02:00 committed by GitHub
commit a8e9f6cc29
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 203 additions and 53 deletions

View File

@ -90,12 +90,22 @@ document_properties_producer=PDF Producer:
document_properties_version=PDF Version:
document_properties_page_count=Page Count:
document_properties_page_size=Page Size:
# LOCALIZATION NOTE (document_properties_page_size_in_2): "{{width}}" and "{{height}}"
# will be replaced by the size of the (current) page, in inches.
document_properties_page_size_in_2={{width}} × {{height}} in
# LOCALIZATION NOTE (document_properties_page_size_mm_2): "{{width}}" and "{{height}}"
# will be replaced by the size of the (current) page, in millimeters.
document_properties_page_size_mm_2={{width}} × {{height}} mm
document_properties_page_size_unit_inches=in
document_properties_page_size_unit_millimeters=mm
document_properties_page_size_orientation_portrait=portrait
document_properties_page_size_orientation_landscape=landscape
document_properties_page_size_name_a3=A3
document_properties_page_size_name_a4=A4
document_properties_page_size_name_letter=Letter
document_properties_page_size_name_legal=Legal
# LOCALIZATION NOTE (document_properties_page_size_dimension_string):
# "{{width}}", "{{height}}", {{unit}}, and {{orientation}} will be replaced by
# the size, respectively their unit of measurement and orientation, of the (current) page.
document_properties_page_size_dimension_string={{width}} × {{height}} {{unit}} ({{orientation}})
# LOCALIZATION NOTE (document_properties_page_size_dimension_name_string):
# "{{width}}", "{{height}}", {{unit}}, {{name}}, and {{orientation}} will be replaced by
# the size, respectively their unit of measurement, name, and orientation, of the (current) page.
document_properties_page_size_dimension_name_string={{width}} × {{height}} {{unit}} ({{name}}, {{orientation}})
document_properties_close=Close
print_progress_message=Preparing document for printing…

View File

@ -90,12 +90,22 @@ document_properties_producer=PDF-producent:
document_properties_version=PDF-version:
document_properties_page_count=Sidantal:
document_properties_page_size=Sidstorlek:
# LOCALIZATION NOTE (document_properties_page_size_in_2): "{{width}}" and "{{height}}"
# will be replaced by the size of the (current) page, in inches.
document_properties_page_size_in_2={{width}} × {{height}} tum
# LOCALIZATION NOTE (document_properties_page_size_mm_2): "{{width}}" and "{{height}}"
# will be replaced by the size of the (current) page, in millimeters.
document_properties_page_size_mm_2={{width}} × {{height}} mm
document_properties_page_size_unit_inches=tum
document_properties_page_size_unit_millimeters=mm
document_properties_page_size_orientation_portrait=stående
document_properties_page_size_orientation_landscape=liggande
document_properties_page_size_name_a3=A3
document_properties_page_size_name_a4=A4
document_properties_page_size_name_letter=Letter
document_properties_page_size_name_legal=Legal
# LOCALIZATION NOTE (document_properties_page_size_dimension_string):
# "{{width}}", "{{height}}", {{unit}}, and {{orientation}} will be replaced by
# the size, respectively their unit of measurement and orientation, of the (current) page.
document_properties_page_size_dimension_string={{width}} × {{height}} {{unit}} ({{orientation}})
# LOCALIZATION NOTE (document_properties_page_size_dimension_name_string):
# "{{width}}", "{{height}}", {{unit}}, {{name}}, and {{orientation}} will be replaced by
# the size, respectively their unit of measurement, name, and orientation, of the (current) page.
document_properties_page_size_dimension_name_string={{width}} × {{height}} {{unit}} ({{name}}, {{orientation}})
document_properties_close=Stäng
print_progress_message=Förbereder sidor för utskrift…

View File

@ -15,7 +15,7 @@
import {
binarySearchFirstItem, EventBus, getPageSizeInches, getPDFFileNameFromURL,
isValidRotation, waitOnEventOrTimeout, WaitOnType
isPortraitOrientation, isValidRotation, waitOnEventOrTimeout, WaitOnType
} from '../../web/ui_utils';
import { createObjectURL } from '../../src/shared/util';
import isNodeJS from '../../src/shared/is_node';
@ -285,6 +285,27 @@ describe('ui_utils', function() {
});
});
describe('isPortraitOrientation', function() {
it('should be portrait orientation', function() {
expect(isPortraitOrientation({
width: 200,
height: 400,
})).toEqual(true);
expect(isPortraitOrientation({
width: 500,
height: 500,
})).toEqual(true);
});
it('should be landscape orientation', function() {
expect(isPortraitOrientation({
width: 600,
height: 300,
})).toEqual(false);
});
});
describe('waitOnEventOrTimeout', function() {
let eventBus;

View File

@ -14,9 +14,10 @@
*/
import {
CSS_UNITS, DEFAULT_SCALE, DEFAULT_SCALE_VALUE, isValidRotation,
MAX_AUTO_SCALE, NullL10n, PresentationModeState, RendererType,
SCROLLBAR_PADDING, TextLayerMode, UNKNOWN_SCALE, VERTICAL_PADDING, watchScroll
CSS_UNITS, DEFAULT_SCALE, DEFAULT_SCALE_VALUE, isPortraitOrientation,
isValidRotation, MAX_AUTO_SCALE, NullL10n, PresentationModeState,
RendererType, SCROLLBAR_PADDING, TextLayerMode, UNKNOWN_SCALE,
VERTICAL_PADDING, watchScroll
} from './ui_utils';
import { PDFRenderingQueue, RenderingStates } from './pdf_rendering_queue';
import { AnnotationLayerBuilder } from './annotation_layer_builder';
@ -94,10 +95,6 @@ function isSameScale(oldScale, newScale) {
return false;
}
function isPortraitOrientation(size) {
return size.width <= size.height;
}
/**
* Simple viewer control to display PDF content/pages.
* @implements {IRenderableView}
@ -578,11 +575,10 @@ class BaseViewer {
scale = Math.min(pageWidthScale, pageHeightScale);
break;
case 'auto':
let isLandscape = (currentPage.width > currentPage.height);
// For pages in landscape mode, fit the page height to the viewer
// *unless* the page would thus become too wide to fit horizontally.
let horizontalScale = isLandscape ?
Math.min(pageHeightScale, pageWidthScale) : pageWidthScale;
let horizontalScale = isPortraitOrientation(currentPage) ?
pageWidthScale : Math.min(pageHeightScale, pageWidthScale);
scale = Math.min(MAX_AUTO_SCALE, horizontalScale);
break;
default:

View File

@ -145,6 +145,10 @@ class MozL10n {
this.mozL10n = mozL10n;
}
getLanguage() {
return Promise.resolve(this.mozL10n.getLanguage());
}
getDirection() {
return Promise.resolve(this.mozL10n.getDirection());
}

View File

@ -27,6 +27,12 @@ class GenericL10n {
});
}
getLanguage() {
return this._ready.then((l10n) => {
return l10n.getLanguage();
});
}
getDirection() {
return this._ready.then((l10n) => {
return l10n.getDirection();

View File

@ -160,6 +160,11 @@ class IPDFAnnotationLayerFactory {
* @interface
*/
class IL10n {
/**
* @returns {Promise<string>} - Resolves to the current locale.
*/
getLanguage() {}
/**
* @returns {Promise<string>} - Resolves to 'rtl' or 'ltr'.
*/

View File

@ -14,12 +14,34 @@
*/
import {
cloneObj, getPageSizeInches, getPDFFileNameFromURL, NullL10n
cloneObj, getPageSizeInches, getPDFFileNameFromURL, isPortraitOrientation,
NullL10n
} from './ui_utils';
import { createPromiseCapability } from 'pdfjs-lib';
const DEFAULT_FIELD_CONTENT = '-';
// See https://en.wikibooks.org/wiki/Lentis/Conversion_to_the_Metric_Standard_in_the_United_States
const NON_METRIC_LOCALES = ['en-us', 'en-lr', 'my'];
// Should use the format: `width x height`, in portrait orientation.
// See https://en.wikipedia.org/wiki/Paper_size
const US_PAGE_NAMES = {
'8.5x11': 'Letter',
'8.5x14': 'Legal',
};
const METRIC_PAGE_NAMES = {
'297x420': 'A3',
'210x297': 'A4',
};
function getPageName(size, isPortrait, pageNames) {
const width = (isPortrait ? size.width : size.height);
const height = (isPortrait ? size.height : size.width);
return pageNames[`${width}x${height}`];
}
/**
* @typedef {Object} PDFDocumentPropertiesOptions
* @property {string} overlayName - Name/identifier for the overlay.
@ -55,7 +77,15 @@ class PDFDocumentProperties {
eventBus.on('pagechanging', (evt) => {
this._currentPageNumber = evt.pageNumber;
});
eventBus.on('rotationchanging', (evt) => {
this._pagesRotation = evt.pagesRotation;
});
}
this._isNonMetricLocale = true; // The default viewer locale is 'en-us'.
l10n.getLanguage().then((locale) => {
this._isNonMetricLocale = NON_METRIC_LOCALES.includes(locale);
});
}
/**
@ -74,11 +104,13 @@ class PDFDocumentProperties {
Promise.all([this.overlayManager.open(this.overlayName),
this._dataAvailableCapability.promise]).then(() => {
const currentPageNumber = this._currentPageNumber;
const pagesRotation = this._pagesRotation;
// If the document properties were previously fetched (for this PDF file),
// just update the dialog immediately to avoid redundant lookups.
if (this.fieldData &&
currentPageNumber === this.fieldData['_currentPageNumber']) {
currentPageNumber === this.fieldData['_currentPageNumber'] &&
pagesRotation === this.fieldData['_pagesRotation']) {
this._updateUI();
return;
}
@ -94,11 +126,12 @@ class PDFDocumentProperties {
this._parseDate(info.CreationDate),
this._parseDate(info.ModDate),
this.pdfDocument.getPage(currentPageNumber).then((pdfPage) => {
return this._parsePageSize(getPageSizeInches(pdfPage));
return this._parsePageSize(getPageSizeInches(pdfPage),
pagesRotation);
}),
]);
}).then(([info, metadata, fileName, fileSize, creationDate, modDate,
pageSizes]) => {
pageSize]) => {
freezeFieldData({
'fileName': fileName,
'fileSize': fileSize,
@ -112,9 +145,9 @@ class PDFDocumentProperties {
'producer': info.Producer,
'version': info.PDFFormatVersion,
'pageCount': this.pdfDocument.numPages,
'pageSizeInch': pageSizes.inch,
'pageSizeMM': pageSizes.mm,
'pageSize': pageSize,
'_currentPageNumber': currentPageNumber,
'_pagesRotation': pagesRotation,
});
this._updateUI();
@ -191,6 +224,7 @@ class PDFDocumentProperties {
delete this.fieldData;
this._dataAvailableCapability = createPromiseCapability();
this._currentPageNumber = 1;
this._pagesRotation = 0;
}
/**
@ -240,27 +274,87 @@ class PDFDocumentProperties {
/**
* @private
*/
_parsePageSize(pageSizeInches) {
_parsePageSize(pageSizeInches, pagesRotation) {
if (!pageSizeInches) {
return Promise.resolve({ inch: undefined, mm: undefined, });
return Promise.resolve(undefined);
}
// Take the viewer rotation into account as well; compare with Adobe Reader.
if (pagesRotation % 180 !== 0) {
pageSizeInches = {
width: pageSizeInches.height,
height: pageSizeInches.width,
};
}
const isPortrait = isPortraitOrientation(pageSizeInches);
let sizeInches = {
width: Math.round(pageSizeInches.width * 100) / 100,
height: Math.round(pageSizeInches.height * 100) / 100,
};
// 1in == 25.4mm; no need to round to 2 decimals for millimeters.
let sizeMillimeters = {
width: Math.round(pageSizeInches.width * 25.4 * 10) / 10,
height: Math.round(pageSizeInches.height * 25.4 * 10) / 10,
};
let pageName = null;
let name = getPageName(sizeInches, isPortrait, US_PAGE_NAMES) ||
getPageName(sizeMillimeters, isPortrait, METRIC_PAGE_NAMES);
if (!name && !(Number.isInteger(sizeMillimeters.width) &&
Number.isInteger(sizeMillimeters.height))) {
// Attempt to improve the page name detection by falling back to fuzzy
// matching of the metric dimensions, to account for e.g. rounding errors
// and/or PDF files that define the page sizes in an imprecise manner.
const exactMillimeters = {
width: pageSizeInches.width * 25.4,
height: pageSizeInches.height * 25.4,
};
const intMillimeters = {
width: Math.round(sizeMillimeters.width),
height: Math.round(sizeMillimeters.height),
};
// Try to avoid false positives, by only considering "small" differences.
if (Math.abs(exactMillimeters.width - intMillimeters.width) < 0.1 &&
Math.abs(exactMillimeters.height - intMillimeters.height) < 0.1) {
name = getPageName(intMillimeters, isPortrait, METRIC_PAGE_NAMES);
if (name) {
// Update *both* sizes, computed above, to ensure that the displayed
// dimensions always correspond to the detected page name.
sizeInches = {
width: Math.round(intMillimeters.width / 25.4 * 100) / 100,
height: Math.round(intMillimeters.height / 25.4 * 100) / 100,
};
sizeMillimeters = intMillimeters;
}
}
}
if (name) {
pageName = this.l10n.get('document_properties_page_size_name_' +
name.toLowerCase(), null, name);
}
const { width, height, } = pageSizeInches;
return Promise.all([
this.l10n.get('document_properties_page_size_in_2', {
width: (Math.round(width * 100) / 100).toLocaleString(),
height: (Math.round(height * 100) / 100).toLocaleString(),
}, '{{width}} × {{height}} in'),
// 1in = 25.4mm; no need to round to 2 decimals for millimeters.
this.l10n.get('document_properties_page_size_mm_2', {
width: (Math.round(width * 25.4 * 10) / 10).toLocaleString(),
height: (Math.round(height * 25.4 * 10) / 10).toLocaleString(),
}, '{{width}} × {{height}} mm'),
]).then((sizes) => {
return {
inch: sizes[0],
mm: sizes[1],
};
(this._isNonMetricLocale ? sizeInches : sizeMillimeters),
this.l10n.get('document_properties_page_size_unit_' +
(this._isNonMetricLocale ? 'inches' : 'millimeters'), null,
this._isNonMetricLocale ? 'in' : 'mm'),
pageName,
this.l10n.get('document_properties_page_size_orientation_' +
(isPortrait ? 'portrait' : 'landscape'), null,
isPortrait ? 'portrait' : 'landscape'),
]).then(([{ width, height, }, unit, name, orientation]) => {
return this.l10n.get('document_properties_page_size_dimension_' +
(name ? 'name_' : '') + 'string', {
width: width.toLocaleString(),
height: height.toLocaleString(),
unit,
name,
orientation,
}, '{{width}} × {{height}} {{unit}} (' +
(name ? '{{name}}, ' : '') + '{{orientation}})');
});
}

View File

@ -58,6 +58,10 @@ function formatL10nValue(text, args) {
* @implements {IL10n}
*/
let NullL10n = {
getLanguage() {
return Promise.resolve('en-us');
},
getDirection() {
return Promise.resolve('ltr');
},
@ -439,6 +443,10 @@ function isValidRotation(angle) {
return Number.isInteger(angle) && angle % 90 === 0;
}
function isPortraitOrientation(size) {
return size.width <= size.height;
}
function cloneObj(obj) {
let result = Object.create(null);
for (let i in obj) {
@ -642,6 +650,7 @@ export {
SCROLLBAR_PADDING,
VERTICAL_PADDING,
isValidRotation,
isPortraitOrientation,
isFileSchema,
cloneObj,
PresentationModeState,

View File

@ -352,11 +352,7 @@ See https://github.com/adobe-type-tools/cmap-resources
<span data-l10n-id="document_properties_page_count">Page Count:</span> <p id="pageCountField">-</p>
</div>
<div class="row">
<span data-l10n-id="document_properties_page_size">Page Size:</span>
<p>
<span id="pageSizeFieldMM">-</span><br>
<span id="pageSizeFieldInch">-</span>
</p>
<span data-l10n-id="document_properties_page_size">Page Size:</span> <p id="pageSizeField">-</p>
</div>
<div class="buttonRow">
<button id="documentPropertiesClose" class="overlayButton"><span data-l10n-id="document_properties_close">Close</span></button>

View File

@ -159,8 +159,7 @@ function getViewerConfiguration() {
'producer': document.getElementById('producerField'),
'version': document.getElementById('versionField'),
'pageCount': document.getElementById('pageCountField'),
'pageSizeInch': document.getElementById('pageSizeFieldInch'),
'pageSizeMM': document.getElementById('pageSizeFieldMM'),
'pageSize': document.getElementById('pageSizeField'),
},
},
errorWrapper: {