1
0
Fork 0
mirror of https://github.com/mozilla/pdf.js.git synced 2025-04-22 16:18:08 +02:00

Merge upstream and change test pdf file.

This commit is contained in:
Brendan Dahl 2011-11-22 10:39:26 -08:00
commit faa202df1e
24 changed files with 4306 additions and 635 deletions

View file

@ -445,7 +445,7 @@ var CanvasGraphics = (function canvasGraphics() {
this.save();
ctx.scale(fontSize, fontSize);
ctx.transform.apply(ctx, fontMatrix);
this.executeIRQueue(glyph.IRQueue);
this.executeIRQueue(glyph.codeIRQueue);
this.restore();
var transformed = Util.applyTransform([glyph.width, 0], fontMatrix);
@ -546,7 +546,9 @@ var CanvasGraphics = (function canvasGraphics() {
setStrokeColor: function canvasGraphicsSetStrokeColor(/*...*/) {
var cs = this.current.strokeColorSpace;
var color = cs.getRgb(arguments);
this.setStrokeRGBColor.apply(this, color);
var color = Util.makeCssRgb.apply(null, cs.getRgb(arguments));
this.ctx.strokeStyle = color;
this.current.strokeColor = color;
},
getColorN_IR_Pattern: function canvasGraphicsGetColorN_IR_Pattern(IR, cs) {
if (IR[0] == 'TilingPattern') {
@ -581,8 +583,9 @@ var CanvasGraphics = (function canvasGraphics() {
},
setFillColor: function canvasGraphicsSetFillColor(/*...*/) {
var cs = this.current.fillColorSpace;
var color = cs.getRgb(arguments);
this.setFillRGBColor.apply(this, color);
var color = Util.makeCssRgb.apply(null, cs.getRgb(arguments));
this.ctx.fillStyle = color;
this.current.fillColor = color;
},
setFillColorN_IR: function canvasGraphicsSetFillColorN(/*...*/) {
var cs = this.current.fillColorSpace;
@ -594,27 +597,49 @@ var CanvasGraphics = (function canvasGraphics() {
}
},
setStrokeGray: function canvasGraphicsSetStrokeGray(gray) {
this.setStrokeRGBColor(gray, gray, gray);
if (!(this.current.strokeColorSpace instanceof DeviceGrayCS))
this.current.strokeColorSpace = new DeviceGrayCS();
var color = Util.makeCssRgb(gray, gray, gray);
this.ctx.strokeStyle = color;
this.current.strokeColor = color;
},
setFillGray: function canvasGraphicsSetFillGray(gray) {
this.setFillRGBColor(gray, gray, gray);
if (!(this.current.fillColorSpace instanceof DeviceGrayCS))
this.current.fillColorSpace = new DeviceGrayCS();
var color = Util.makeCssRgb(gray, gray, gray);
this.ctx.fillStyle = color;
this.current.fillColor = color;
},
setStrokeRGBColor: function canvasGraphicsSetStrokeRGBColor(r, g, b) {
if (!(this.current.strokeColorSpace instanceof DeviceRgbCS))
this.current.strokeColorSpace = new DeviceRgbCS();
var color = Util.makeCssRgb(r, g, b);
this.ctx.strokeStyle = color;
this.current.strokeColor = color;
},
setFillRGBColor: function canvasGraphicsSetFillRGBColor(r, g, b) {
if (!(this.current.fillColorSpace instanceof DeviceRgbCS))
this.current.fillColorSpace = new DeviceRgbCS();
var color = Util.makeCssRgb(r, g, b);
this.ctx.fillStyle = color;
this.current.fillColor = color;
},
setStrokeCMYKColor: function canvasGraphicsSetStrokeCMYKColor(c, m, y, k) {
if (!(this.current.strokeColorSpace instanceof DeviceCmykCS))
this.current.strokeColorSpace = new DeviceCmykCS();
var color = Util.makeCssCmyk(c, m, y, k);
this.ctx.strokeStyle = color;
this.current.strokeColor = color;
},
setFillCMYKColor: function canvasGraphicsSetFillCMYKColor(c, m, y, k) {
if (!(this.current.fillColorSpace instanceof DeviceCmykCS))
this.current.fillColorSpace = new DeviceCmykCS();
var color = Util.makeCssCmyk(c, m, y, k);
this.ctx.fillStyle = color;
this.current.fillColor = color;

View file

@ -24,7 +24,7 @@ var ColorSpace = (function colorSpaceColorSpace() {
constructor.parse = function colorSpaceParse(cs, xref, res) {
var IR = constructor.parseToIR(cs, xref, res);
if (IR instanceof SeparationCS)
if (IR instanceof AlternateCS)
return IR;
return constructor.fromIR(IR);
@ -50,11 +50,12 @@ var ColorSpace = (function colorSpaceColorSpace() {
var hiVal = IR[2];
var lookup = IR[3];
return new IndexedCS(ColorSpace.fromIR(baseIndexedCS), hiVal, lookup);
case 'SeparationCS':
var alt = IR[1];
var tintFnIR = IR[2];
case 'AlternateCS':
var numComps = IR[1];
var alt = IR[2];
var tintFnIR = IR[3];
return new SeparationCS(ColorSpace.fromIR(alt),
return new AlternateCS(numComps, ColorSpace.fromIR(alt),
PDFFunction.fromIR(tintFnIR));
default:
error('Unkown name ' + name);
@ -134,11 +135,17 @@ var ColorSpace = (function colorSpaceColorSpace() {
var lookup = xref.fetchIfRef(cs[3]);
return ['IndexedCS', baseIndexedCS, hiVal, lookup];
case 'Separation':
case 'DeviceN':
var name = cs[1];
var numComps = 1;
if (isName(name))
numComps = 1;
else if (isArray(name))
numComps = name.length;
var alt = ColorSpace.parseToIR(cs[2], xref, res);
var tintFnIR = PDFFunction.getIR(xref, xref.fetchIfRef(cs[3]));
return ['SeparationCS', alt, tintFnIR];
return ['AlternateCS', numComps, alt, tintFnIR];
case 'Lab':
case 'DeviceN':
default:
error('unimplemented color space object "' + mode + '"');
}
@ -151,33 +158,45 @@ var ColorSpace = (function colorSpaceColorSpace() {
return constructor;
})();
var SeparationCS = (function separationCS() {
function constructor(base, tintFn) {
this.name = 'Separation';
this.numComps = 1;
this.defaultColor = [1];
/**
* Alternate color space handles both Separation and DeviceN color spaces. A
* Separation color space is actually just a DeviceN with one color component.
* Both color spaces use a tinting function to convert colors to a base color
* space.
*/
var AlternateCS = (function alternateCS() {
function constructor(numComps, base, tintFn) {
this.name = 'Alternate';
this.numComps = numComps;
this.defaultColor = [];
for (var i = 0; i < numComps; ++i)
this.defaultColor.push(1);
this.base = base;
this.tintFn = tintFn;
}
constructor.prototype = {
getRgb: function sepcs_getRgb(color) {
getRgb: function altcs_getRgb(color) {
var tinted = this.tintFn(color);
return this.base.getRgb(tinted);
},
getRgbBuffer: function sepcs_getRgbBuffer(input, bits) {
getRgbBuffer: function altcs_getRgbBuffer(input, bits) {
var tintFn = this.tintFn;
var base = this.base;
var scale = 1 / ((1 << bits) - 1);
var length = input.length;
var pos = 0;
var numComps = base.numComps;
var baseBuf = new Uint8Array(numComps * length);
var baseNumComps = base.numComps;
var baseBuf = new Uint8Array(baseNumComps * length);
var numComps = this.numComps;
var scaled = new Array(numComps);
for (var i = 0; i < length; ++i) {
var scaled = input[i] * scale;
var tinted = tintFn([scaled]);
for (var j = 0; j < numComps; ++j)
for (var i = 0; i < length; i += numComps) {
for (var z = 0; z < numComps; ++z)
scaled[z] = input[i + z] * scale;
var tinted = tintFn(scaled);
for (var j = 0; j < baseNumComps; ++j)
baseBuf[pos++] = 255 * tinted[j];
}
return base.getRgbBuffer(baseBuf, 8);

View file

@ -15,10 +15,6 @@ if (!globalScope.PDFJS) {
globalScope.PDFJS = {};
}
// Temporarily disabling workers until 'localhost' FF bugfix lands:
// https://bugzilla.mozilla.org/show_bug.cgi?id=683280
globalScope.PDFJS.disableWorker = true;
// getPdf()
// Convenience function to perform binary Ajax GET
// Usage: getPdf('http://...', callback)
@ -471,6 +467,7 @@ var PDFDoc = (function pdfDoc() {
this.objs = new PDFObjects();
this.pageCache = [];
this.fontsLoading = {};
this.workerReadyPromise = new Promise('workerReady');
// If worker support isn't disabled explicit and the browser has worker
@ -484,7 +481,16 @@ var PDFDoc = (function pdfDoc() {
throw 'No PDFJS.workerSrc specified';
}
var worker = new Worker(workerSrc);
var worker;
try {
worker = new Worker(workerSrc);
} catch (e) {
// Some versions of FF can't create a worker on localhost, see:
// https://bugzilla.mozilla.org/show_bug.cgi?id=683280
globalScope.PDFJS.disableWorker = true;
this.setupFakeWorker();
return;
}
var messageHandler = new MessageHandler('main', worker);
@ -505,8 +511,6 @@ var PDFDoc = (function pdfDoc() {
} else {
this.setupFakeWorker();
}
this.fontsLoading = {};
}
constructor.prototype = {

View file

@ -459,18 +459,183 @@ var PartialEvaluator = (function partialEvaluator() {
};
},
extractEncoding: function partialEvaluatorExtractEncoding(dict,
xref,
properties) {
var type = properties.type, encoding;
if (properties.composite) {
var defaultWidth = xref.fetchIfRef(dict.get('DW')) || 1000;
properties.defaultWidth = defaultWidth;
extractDataStructures: function
partialEvaluatorExtractDataStructures(dict, baseDict,
xref, properties) {
// 9.10.2
var toUnicode = dict.get('ToUnicode') ||
baseDict.get('ToUnicode');
if (toUnicode)
properties.toUnicode = this.readToUnicode(toUnicode, xref);
if (properties.composite) {
// CIDSystemInfo helps to match CID to glyphs
var cidSystemInfo = xref.fetchIfRef(dict.get('CIDSystemInfo'));
if (isDict(cidSystemInfo)) {
properties.cidSystemInfo = {
registry: cidSystemInfo.get('Registry'),
ordering: cidSystemInfo.get('Ordering'),
supplement: cidSystemInfo.get('Supplement')
};
}
var cidToGidMap = xref.fetchIfRef(dict.get('CIDToGIDMap'));
if (isStream(cidToGidMap))
properties.cidToGidMap = this.readCidToGidMap(cidToGidMap);
}
var differences = [];
var baseEncoding = Encodings.StandardEncoding;
var hasEncoding = dict.has('Encoding');
if (hasEncoding) {
var encoding = xref.fetchIfRef(dict.get('Encoding'));
if (isDict(encoding)) {
var baseName = encoding.get('BaseEncoding');
if (baseName)
baseEncoding = Encodings[baseName.name];
// Load the differences between the base and original
if (encoding.has('Differences')) {
var diffEncoding = encoding.get('Differences');
var index = 0;
for (var j = 0, jj = diffEncoding.length; j < jj; j++) {
var data = diffEncoding[j];
if (isNum(data))
index = data;
else
differences[index++] = data.name;
}
}
} else if (isName(encoding)) {
baseEncoding = Encodings[encoding.name];
} else {
error('Encoding is not a Name nor a Dict');
}
}
properties.differences = differences;
properties.baseEncoding = baseEncoding;
properties.hasEncoding = hasEncoding;
},
readToUnicode:
function partialEvaluatorReadToUnicode(toUnicode, xref) {
var cmapObj = xref.fetchIfRef(toUnicode);
var charToUnicode = [];
if (isName(cmapObj)) {
var isIdentityMap = cmapObj.name.substr(0, 9) == 'Identity-';
if (!isIdentityMap)
error('ToUnicode file cmap translation not implemented');
} else if (isStream(cmapObj)) {
var tokens = [];
var token = '';
var beginArrayToken = {};
var cmap = cmapObj.getBytes(cmapObj.length);
for (var i = 0, ii = cmap.length; i < ii; i++) {
var byte = cmap[i];
if (byte == 0x20 || byte == 0x0D || byte == 0x0A ||
byte == 0x3C || byte == 0x5B || byte == 0x5D) {
switch (token) {
case 'usecmap':
error('usecmap is not implemented');
break;
case 'beginbfchar':
case 'beginbfrange':
case 'begincidchar':
case 'begincidrange':
token = '';
tokens = [];
break;
case 'endcidrange':
case 'endbfrange':
for (var j = 0, jj = tokens.length; j < jj; j += 3) {
var startRange = tokens[j];
var endRange = tokens[j + 1];
var code = tokens[j + 2];
while (startRange <= endRange) {
charToUnicode[startRange] = code++;
++startRange;
}
}
break;
case 'endcidchar':
case 'endbfchar':
for (var j = 0, jj = tokens.length; j < jj; j += 2) {
var index = tokens[j];
var code = tokens[j + 1];
charToUnicode[index] = code;
}
break;
case '':
break;
default:
if (token[0] >= '0' && token[0] <= '9')
token = parseInt(token, 10); // a number
tokens.push(token);
token = '';
}
switch (byte) {
case 0x5B:
// begin list parsing
tokens.push(beginArrayToken);
break;
case 0x5D:
// collect array items
var items = [], item;
while (tokens.length &&
(item = tokens.pop()) != beginArrayToken)
items.unshift(item);
tokens.push(items);
break;
}
} else if (byte == 0x3E) {
if (token.length) {
// parsing hex number
tokens.push(parseInt(token, 16));
token = '';
}
} else {
token += String.fromCharCode(byte);
}
}
}
return charToUnicode;
},
readCidToGidMap:
function partialEvaluatorReadCidToGidMap(cidToGidStream) {
// Extract the encoding from the CIDToGIDMap
var glyphsData = cidToGidStream.getBytes();
// Set encoding 0 to later verify the font has an encoding
var result = [];
for (var j = 0, jj = glyphsData.length; j < jj; j++) {
var glyphID = (glyphsData[j++] << 8) | glyphsData[j];
if (glyphID == 0)
continue;
var code = j >> 1;
result[code] = glyphID;
}
return result;
},
extractWidths: function partialEvaluatorWidths(dict,
xref,
descriptor,
properties) {
var glyphsWidths = [];
var defaultWidth = 0;
if (properties.composite) {
defaultWidth = xref.fetchIfRef(dict.get('DW')) || 1000;
var glyphsWidths = {};
var widths = xref.fetchIfRef(dict.get('W'));
if (widths) {
var start = 0;
var start = 0, end = 0;
for (var i = 0, ii = widths.length; i < ii; i++) {
var code = widths[i];
if (isArray(code)) {
@ -487,247 +652,42 @@ var PartialEvaluator = (function partialEvaluator() {
}
}
}
properties.widths = glyphsWidths;
// Glyph ids are big-endian 2-byte values
encoding = properties.encoding;
// CIDSystemInfo might help to match width and glyphs
var cidSystemInfo = dict.get('CIDSystemInfo');
if (isDict(cidSystemInfo)) {
properties.cidSystemInfo = {
registry: cidSystemInfo.get('Registry'),
ordering: cidSystemInfo.get('Ordering'),
supplement: cidSystemInfo.get('Supplement')
};
}
var cidToGidMap = dict.get('CIDToGIDMap');
if (!cidToGidMap || !isRef(cidToGidMap)) {
return Object.create(GlyphsUnicode);
}
// Extract the encoding from the CIDToGIDMap
var glyphsStream = xref.fetchIfRef(cidToGidMap);
var glyphsData = glyphsStream.getBytes(0);
// Set encoding 0 to later verify the font has an encoding
encoding[0] = { unicode: 0, width: 0 };
for (var j = 0, jj = glyphsData.length; j < jj; j++) {
var glyphID = (glyphsData[j++] << 8) | glyphsData[j];
if (glyphID == 0)
continue;
var code = j >> 1;
var width = glyphsWidths[code];
encoding[code] = {
unicode: glyphID,
width: isNum(width) ? width : defaultWidth
};
}
return Object.create(GlyphsUnicode);
}
var differences = properties.differences;
var map = properties.encoding;
var baseEncoding = null;
if (dict.has('Encoding')) {
encoding = xref.fetchIfRef(dict.get('Encoding'));
if (isDict(encoding)) {
var baseName = encoding.get('BaseEncoding');
if (baseName)
baseEncoding = Encodings[baseName.name].slice();
// Load the differences between the base and original
if (encoding.has('Differences')) {
var diffEncoding = encoding.get('Differences');
var index = 0;
for (var j = 0, jj = diffEncoding.length; j < jj; j++) {
var data = diffEncoding[j];
if (isNum(data))
index = data;
else
differences[index++] = data.name;
}
}
} else if (isName(encoding)) {
baseEncoding = Encodings[encoding.name].slice();
} else {
var firstChar = properties.firstChar;
var widths = xref.fetchIfRef(dict.get('Widths'));
if (widths) {
var j = firstChar;
for (var i = 0, ii = widths.length; i < ii; i++)
glyphsWidths[j++] = widths[i];
defaultWidth = parseFloat(descriptor.get('MissingWidth')) || 0;
} else {
error('Encoding is not a Name nor a Dict');
}
}
// Trying get the BaseFont metrics (see comment above).
var baseFontName = dict.get('BaseFont');
if (isName(baseFontName)) {
var metrics = this.getBaseFontMetrics(baseFontName.name);
if (!baseEncoding) {
switch (type) {
case 'TrueType':
baseEncoding = Encodings.WinAnsiEncoding.slice();
break;
case 'Type1':
case 'Type3':
baseEncoding = Encodings.StandardEncoding.slice();
break;
default:
warn('Unknown type of font: ' + type);
baseEncoding = [];
break;
}
}
// merge in the differences
var firstChar = properties.firstChar;
var lastChar = properties.lastChar;
var widths = properties.widths || [];
var glyphs = {};
for (var i = firstChar; i <= lastChar; i++) {
var glyph = differences[i];
var replaceGlyph = true;
if (!glyph) {
glyph = baseEncoding[i] || i;
replaceGlyph = false;
}
var index = GlyphsUnicode[glyph] || i;
var width = widths[i] || widths[glyph];
map[i] = {
unicode: index,
width: isNum(width) ? width : properties.defaultWidth
};
if (replaceGlyph || !glyphs[glyph])
glyphs[glyph] = map[i];
if (replaceGlyph || !glyphs[index])
glyphs[index] = map[i];
// If there is no file, the character mapping can't be modified
// but this is unlikely that there is any standard encoding with
// chars below 0x1f, so that's fine.
if (!properties.file)
continue;
if (index <= 0x1f || (index >= 127 && index <= 255))
map[i].unicode += kCmapGlyphOffset;
}
if (type == 'TrueType' && dict.has('ToUnicode') && differences) {
var cmapObj = dict.get('ToUnicode');
if (isRef(cmapObj)) {
cmapObj = xref.fetch(cmapObj);
}
if (isName(cmapObj)) {
error('ToUnicode file cmap translation not implemented');
} else if (isStream(cmapObj)) {
var tokens = [];
var token = '';
var beginArrayToken = {};
var cmap = cmapObj.getBytes(cmapObj.length);
for (var i = 0, ii = cmap.length; i < ii; i++) {
var byte = cmap[i];
if (byte == 0x20 || byte == 0x0D || byte == 0x0A ||
byte == 0x3C || byte == 0x5B || byte == 0x5D) {
switch (token) {
case 'usecmap':
error('usecmap is not implemented');
break;
case 'beginbfchar':
case 'beginbfrange':
case 'begincidchar':
case 'begincidrange':
token = '';
tokens = [];
break;
case 'endcidrange':
case 'endbfrange':
for (var j = 0, jj = tokens.length; j < jj; j += 3) {
var startRange = tokens[j];
var endRange = tokens[j + 1];
var code = tokens[j + 2];
while (startRange < endRange) {
var mapping = map[startRange] || {};
mapping.unicode = code++;
map[startRange] = mapping;
++startRange;
}
}
break;
case 'endcidchar':
case 'endbfchar':
for (var j = 0, jj = tokens.length; j < jj; j += 2) {
var index = tokens[j];
var code = tokens[j + 1];
var mapping = map[index] || {};
mapping.unicode = code;
map[index] = mapping;
}
break;
case '':
break;
default:
if (token[0] >= '0' && token[0] <= '9')
token = parseInt(token, 10); // a number
tokens.push(token);
token = '';
}
switch (byte) {
case 0x5B:
// begin list parsing
tokens.push(beginArrayToken);
break;
case 0x5D:
// collect array items
var items = [], item;
while (tokens.length &&
(item = tokens.pop()) != beginArrayToken)
items.unshift(item);
tokens.push(items);
break;
}
} else if (byte == 0x3E) {
if (token.length) {
// parsing hex number
tokens.push(parseInt(token, 16));
token = '';
}
} else {
token += String.fromCharCode(byte);
}
glyphsWidths = metrics.widths;
defaultWidth = metrics.defaultWidth;
}
}
}
return glyphs;
properties.defaultWidth = defaultWidth;
properties.widths = glyphsWidths;
},
getBaseFontMetricsAndMap: function getBaseFontMetricsAndMap(name) {
var map = {};
if (/^Symbol(-?(Bold|Italic))*$/.test(name)) {
// special case for symbols
var encoding = Encodings.symbolsEncoding.slice();
for (var i = 0, n = encoding.length, j; i < n; i++) {
j = encoding[i];
if (!j)
continue;
map[i] = GlyphsUnicode[j] || 0;
}
}
var defaultWidth = 0;
var widths = Metrics[stdFontMap[name] || name];
if (isNum(widths)) {
defaultWidth = widths;
widths = null;
getBaseFontMetrics: function getBaseFontMetrics(name) {
var defaultWidth = 0, widths = [];
var glyphWidths = Metrics[stdFontMap[name] || name];
if (isNum(glyphWidths)) {
defaultWidth = glyphWidths;
} else {
widths = glyphWidths;
}
return {
defaultWidth: defaultWidth,
widths: widths || [],
map: map
widths: widths
};
},
@ -756,6 +716,7 @@ var PartialEvaluator = (function partialEvaluator() {
assertWellFormed(isName(type), 'invalid font Subtype');
composite = true;
}
var maxCharIndex = composite ? 0xFFFF : 0xFF;
var descriptor = xref.fetchIfRef(dict.get('FontDescriptor'));
if (!descriptor) {
@ -774,18 +735,16 @@ var PartialEvaluator = (function partialEvaluator() {
// Using base font name as a font name.
baseFontName = baseFontName.name.replace(/[,_]/g, '-');
var metricsAndMap = this.getBaseFontMetricsAndMap(baseFontName);
var metrics = this.getBaseFontMetrics(baseFontName);
var properties = {
type: type.name,
encoding: metricsAndMap.map,
differences: [],
widths: metricsAndMap.widths,
defaultWidth: metricsAndMap.defaultWidth,
widths: metrics.widths,
defaultWidth: metrics.defaultWidth,
firstChar: 0,
lastChar: 256
lastChar: maxCharIndex
};
this.extractEncoding(dict, xref, properties);
this.extractDataStructures(dict, dict, xref, properties);
return {
name: baseFontName,
@ -802,27 +761,7 @@ var PartialEvaluator = (function partialEvaluator() {
// TODO Fill the width array depending on which of the base font this is
// a variant.
var firstChar = xref.fetchIfRef(dict.get('FirstChar')) || 0;
var lastChar = xref.fetchIfRef(dict.get('LastChar')) || 256;
var defaultWidth = 0;
var glyphWidths = {};
var encoding = {};
var widths = xref.fetchIfRef(dict.get('Widths'));
if (widths) {
for (var i = 0, j = firstChar, ii = widths.length; i < ii; i++, j++)
glyphWidths[j] = widths[i];
defaultWidth = parseFloat(descriptor.get('MissingWidth')) || 0;
} else {
// Trying get the BaseFont metrics (see comment above).
var baseFontName = dict.get('BaseFont');
if (isName(baseFontName)) {
var metricsAndMap = this.getBaseFontMetricsAndMap(baseFontName.name);
glyphWidths = metricsAndMap.widths;
defaultWidth = metricsAndMap.defaultWidth;
encoding = metricsAndMap.map;
}
}
var lastChar = xref.fetchIfRef(dict.get('LastChar')) || maxCharIndex;
var fontName = xref.fetchIfRef(descriptor.get('FontName'));
assertWellFormed(isName(fontName), 'invalid font name');
@ -854,34 +793,30 @@ var PartialEvaluator = (function partialEvaluator() {
fixedPitch: false,
fontMatrix: dict.get('FontMatrix') || IDENTITY_MATRIX,
firstChar: firstChar || 0,
lastChar: lastChar || 256,
lastChar: lastChar || maxCharIndex,
bbox: descriptor.get('FontBBox'),
ascent: descriptor.get('Ascent'),
descent: descriptor.get('Descent'),
xHeight: descriptor.get('XHeight'),
capHeight: descriptor.get('CapHeight'),
defaultWidth: defaultWidth,
flags: descriptor.get('Flags'),
italicAngle: descriptor.get('ItalicAngle'),
differences: [],
widths: glyphWidths,
encoding: encoding,
coded: false
};
properties.glyphs = this.extractEncoding(dict, xref, properties);
this.extractWidths(dict, xref, descriptor, properties);
this.extractDataStructures(dict, baseDict, xref, properties);
if (type.name === 'Type3') {
properties.coded = true;
var charProcs = xref.fetchIfRef(dict.get('CharProcs'));
var fontResources = xref.fetchIfRef(dict.get('Resources')) || resources;
properties.resources = fontResources;
properties.charProcIRQueues = {};
for (var key in charProcs.map) {
var glyphStream = xref.fetchIfRef(charProcs.map[key]);
var queueObj = {};
properties.glyphs[key].IRQueue = this.getIRQueue(glyphStream,
fontResources,
queueObj,
dependency);
properties.charProcIRQueues[key] =
this.getIRQueue(glyphStream, fontResources, queueObj, dependency);
}
}

File diff suppressed because it is too large Load diff

View file

@ -20,6 +20,8 @@ var PDFFunction = (function pdfFunction() {
var array = [];
var codeSize = 0;
var codeBuf = 0;
// 32 is a valid bps so shifting won't work
var sampleMul = 1.0 / (Math.pow(2.0, bps) - 1);
var strBytes = str.getBytes((length * bps + 7) / 8);
var strIdx = 0;
@ -30,7 +32,7 @@ var PDFFunction = (function pdfFunction() {
codeSize += 8;
}
codeSize -= bps;
array.push(codeBuf >> codeSize);
array.push((codeBuf >> codeSize) * sampleMul);
codeBuf &= (1 << codeSize) - 1;
}
return array;
@ -76,6 +78,17 @@ var PDFFunction = (function pdfFunction() {
},
constructSampled: function pdfFunctionConstructSampled(str, dict) {
function toMultiArray(arr) {
var inputLength = arr.length;
var outputLength = arr.length / 2;
var out = new Array(outputLength);
var index = 0;
for (var i = 0; i < inputLength; i += 2) {
out[index] = [arr[i], arr[i + 1]];
++index;
}
return out;
}
var domain = dict.get('Domain');
var range = dict.get('Range');
@ -85,9 +98,8 @@ var PDFFunction = (function pdfFunction() {
var inputSize = domain.length / 2;
var outputSize = range.length / 2;
if (inputSize != 1)
error('No support for multi-variable inputs to functions: ' +
inputSize);
domain = toMultiArray(domain);
range = toMultiArray(range);
var size = dict.get('Size');
var bps = dict.get('BitsPerSample');
@ -105,15 +117,36 @@ var PDFFunction = (function pdfFunction() {
encode.push(size[i] - 1);
}
}
encode = toMultiArray(encode);
var decode = dict.get('Decode');
if (!decode)
decode = range;
else
decode = toMultiArray(decode);
// Precalc the multipliers
var inputMul = new Float64Array(inputSize);
for (var i = 0; i < inputSize; ++i) {
inputMul[i] = (encode[i][1] - encode[i][0]) /
(domain[i][1] - domain[i][0]);
}
var idxMul = new Int32Array(inputSize);
idxMul[0] = outputSize;
for (i = 1; i < inputSize; ++i) {
idxMul[i] = idxMul[i - 1] * size[i - 1];
}
var nSamples = outputSize;
for (i = 0; i < inputSize; ++i)
nSamples *= size[i];
var samples = this.getSampleArray(size, outputSize, bps, str);
return [
CONSTRUCT_SAMPLED, inputSize, domain, encode, decode, samples, size,
outputSize, bps, range
outputSize, bps, range, inputMul, idxMul, nSamples
];
},
@ -127,64 +160,74 @@ var PDFFunction = (function pdfFunction() {
var outputSize = IR[7];
var bps = IR[8];
var range = IR[9];
var inputMul = IR[10];
var idxMul = IR[11];
var nSamples = IR[12];
return function constructSampledFromIRResult(args) {
var clip = function constructSampledFromIRClip(v, min, max) {
if (v > max)
v = max;
else if (v < min)
v = min;
return v;
};
if (inputSize != args.length)
error('Incorrect number of arguments: ' + inputSize + ' != ' +
args.length);
// Most of the below is a port of Poppler's implementation.
// TODO: There's a few other ways to do multilinear interpolation such
// as piecewise, which is much faster but an approximation.
var out = new Float64Array(outputSize);
var x;
var e = new Array(inputSize);
var efrac0 = new Float64Array(inputSize);
var efrac1 = new Float64Array(inputSize);
var sBuf = new Float64Array(1 << inputSize);
var i, j, k, idx, t;
for (var i = 0; i < inputSize; i++) {
var i2 = i * 2;
// clip to the domain
var v = clip(args[i], domain[i2], domain[i2 + 1]);
// encode
v = encode[i2] + ((v - domain[i2]) *
(encode[i2 + 1] - encode[i2]) /
(domain[i2 + 1] - domain[i2]));
// clip to the size
args[i] = clip(v, 0, size[i] - 1);
// map input values into sample array
for (i = 0; i < inputSize; ++i) {
x = (args[i] - domain[i][0]) * inputMul[i] + encode[i][0];
if (x < 0) {
x = 0;
} else if (x > size[i] - 1) {
x = size[i] - 1;
}
e[i] = [Math.floor(x), 0];
if ((e[i][1] = e[i][0] + 1) >= size[i]) {
// this happens if in[i] = domain[i][1]
e[i][1] = e[i][0];
}
efrac1[i] = x - e[i][0];
efrac0[i] = 1 - efrac1[i];
}
// interpolate to table
TODO('Multi-dimensional interpolation');
var floor = Math.floor(args[0]);
var ceil = Math.ceil(args[0]);
var scale = args[0] - floor;
// for each output, do m-linear interpolation
for (i = 0; i < outputSize; ++i) {
floor *= outputSize;
ceil *= outputSize;
var output = [], v = 0;
for (var i = 0; i < outputSize; ++i) {
if (ceil == floor) {
v = samples[ceil + i];
} else {
var low = samples[floor + i];
var high = samples[ceil + i];
v = low * scale + high * (1 - scale);
// pull 2^m values out of the sample array
for (j = 0; j < (1 << inputSize); ++j) {
idx = i;
for (k = 0, t = j; k < inputSize; ++k, t >>= 1) {
idx += idxMul[k] * (e[k][t & 1]);
}
if (idx >= 0 && idx < nSamples) {
sBuf[j] = samples[idx];
} else {
sBuf[j] = 0; // TODO Investigate if this is what Adobe does
}
}
var i2 = i * 2;
// decode
v = decode[i2] + (v * (decode[i2 + 1] - decode[i2]) /
((1 << bps) - 1));
// do m sets of interpolations
for (j = 0, t = (1 << inputSize); j < inputSize; ++j, t >>= 1) {
for (k = 0; k < t; k += 2) {
sBuf[k >> 1] = efrac0[j] * sBuf[k] + efrac1[j] * sBuf[k + 1];
}
}
// clip to the domain
output.push(clip(v, range[i2], range[i2 + 1]));
// map output value to range
out[i] = (sBuf[0] * (decode[i][1] - decode[i][0]) + decode[i][0]);
if (out[i] < range[i][0]) {
out[i] = range[i][0];
} else if (out[i] > range[i][1]) {
out[i] = range[i][1];
}
}
return output;
return out;
}
},

View file

@ -19,10 +19,10 @@ var Pattern = (function patternPattern() {
constructor.shadingFromIR = function pattern_shadingFromIR(ctx, raw) {
return Shadings[raw[0]].fromIR(ctx, raw);
}
};
constructor.parseShading = function pattern_shading(shading, matrix,
xref, res, ctx) {
constructor.parseShading = function pattern_shading(shading, matrix, xref,
res, ctx) {
var dict = isStream(shading) ? shading.dict : shading;
var type = dict.get('ShadingType');
@ -116,17 +116,18 @@ Shadings.RadialAxial = (function radialAxialShading() {
p1 = Util.applyTransform(p1, userMatrix);
}
var grad;
if (type == 2)
var grad = ctx.createLinearGradient(p0[0], p0[1], p1[0], p1[1]);
grad = ctx.createLinearGradient(p0[0], p0[1], p1[0], p1[1]);
else if (type == 3)
var grad = ctx.createRadialGradient(p0[0], p0[1], r0, p1[0], p1[1], r1);
grad = ctx.createRadialGradient(p0[0], p0[1], r0, p1[0], p1[1], r1);
for (var i = 0, ii = colorStops.length; i < ii; ++i) {
var c = colorStops[i];
grad.addColorStop(c[0], c[1]);
}
return grad;
}
};
constructor.prototype = {
getIR: function radialAxialShadingGetIR() {
@ -166,7 +167,7 @@ Shadings.Dummy = (function dummyShading() {
constructor.fromIR = function dummyShadingFromIR() {
return 'hotpink';
}
};
constructor.prototype = {
getIR: function dummyShadingGetIR() {
@ -242,9 +243,9 @@ var TilingPattern = (function tilingPattern() {
graphics.transform.apply(graphics, tmpTranslate);
if (bbox && isArray(bbox) && 4 == bbox.length) {
var bboxWidth = bbox[2] - bbox[0];
var bboxHeight = bbox[3] - bbox[1];
graphics.rectangle(bbox[0], bbox[1], bboxWidth, bboxHeight);
var bboxWidth = x1 - x0;
var bboxHeight = y1 - y0;
graphics.rectangle(x0, y0, bboxWidth, bboxHeight);
graphics.clip();
graphics.endPath();
}
@ -264,7 +265,7 @@ var TilingPattern = (function tilingPattern() {
return [
'TilingPattern', args, codeIR, matrix, bbox, xstep, ystep, paintType
];
}
};
TilingPattern.prototype = {
getPattern: function tiling_getPattern() {

View file

@ -7,8 +7,9 @@ var PDFJS = {};
// Use strict in our context only - users might not want it
'use strict';
PDFJS.build = 'PDFJSSCRIPT_BUNDLE_VER';
// Files are inserted below - see Makefile
/* PDFJSSCRIPT_INCLUDE_ALL */
}).call((typeof window === 'undefined') ? this : window);