pdf-lib
Version:
Library for creating and modifying PDF files in JavaScript
123 lines (122 loc) • 6.73 kB
JavaScript
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
}
Object.defineProperty(exports, "__esModule", { value: true });
var pako_1 = __importDefault(require("pako"));
var png_ts_1 = __importDefault(require("png-ts"));
var pdf_objects_1 = require("../../pdf-objects");
var validate_1 = require("../../../utils/validate");
/**
* A note of thanks to the developers of https://github.com/devongovett/pdfkit,
* as this class borrows heavily from:
* https://github.com/devongovett/pdfkit/blob/e71edab0dd4657b5a767804ba86c94c58d01fbca/lib/image/png.coffee
*/
var PNGXObjectFactory = /** @class */ (function () {
function PNGXObjectFactory(data) {
var _this = this;
this.embedImageIn = function (document) {
_this.document = document;
_this.xObjDict = pdf_objects_1.PDFDictionary.from({
Type: pdf_objects_1.PDFName.from('XObject'),
Subtype: pdf_objects_1.PDFName.from('Image'),
BitsPerComponent: pdf_objects_1.PDFNumber.fromNumber(_this.image.bits),
Width: pdf_objects_1.PDFNumber.fromNumber(_this.width),
Height: pdf_objects_1.PDFNumber.fromNumber(_this.height),
Filter: pdf_objects_1.PDFName.from('FlateDecode'),
}, document.index);
if (!_this.image.hasAlphaChannel) {
var params = pdf_objects_1.PDFDictionary.from({
Predictor: pdf_objects_1.PDFNumber.fromNumber(15),
Colors: pdf_objects_1.PDFNumber.fromNumber(_this.image.colors),
BitsPerComponent: pdf_objects_1.PDFNumber.fromNumber(_this.image.bits),
Columns: pdf_objects_1.PDFNumber.fromNumber(_this.width),
}, document.index);
_this.xObjDict.set('DecodeParms', params);
}
if (_this.image.palette.length === 0) {
_this.xObjDict.set('ColorSpace', pdf_objects_1.PDFName.from(_this.image.colorSpace));
}
else {
var paletteStream = document.register(pdf_objects_1.PDFRawStream.from(pdf_objects_1.PDFDictionary.from({
Length: pdf_objects_1.PDFNumber.fromNumber(_this.image.palette.length),
}, document.index), new Uint8Array(_this.image.palette)));
_this.xObjDict.set('ColorSpace', pdf_objects_1.PDFArray.fromArray([
pdf_objects_1.PDFName.from('Indexed'),
pdf_objects_1.PDFName.from('DeviceRGB'),
pdf_objects_1.PDFNumber.fromNumber(_this.image.palette.length / 3 - 1),
paletteStream,
], document.index));
}
// TODO: Handle the following two transparency types. They don't seem to be
// fully handled in:
// https://github.com/devongovett/pdfkit/blob/e71edab0dd4657b5a767804ba86c94c58d01fbca/lib/image/png.coffee
// if (this.image.transparency.grayscale)
// if (this.image.transparency.rgb)
// prettier-ignore
return (_this.image.transparency.indexed ? _this.loadIndexedAlphaChannel()
: _this.image.hasAlphaChannel ? _this.splitAlphaChannel()
: _this.finalize());
};
/** @hidden */
this.finalize = function () {
if (_this.alphaChannel) {
var deflatedAlphaChannel = pako_1.default.deflate(_this.alphaChannel);
var alphaStreamDict = pdf_objects_1.PDFDictionary.from({
Type: pdf_objects_1.PDFName.from('XObject'),
Subtype: pdf_objects_1.PDFName.from('Image'),
Height: pdf_objects_1.PDFNumber.fromNumber(_this.height),
Width: pdf_objects_1.PDFNumber.fromNumber(_this.width),
BitsPerComponent: pdf_objects_1.PDFNumber.fromNumber(8),
Filter: pdf_objects_1.PDFName.from('FlateDecode'),
ColorSpace: pdf_objects_1.PDFName.from('DeviceGray'),
Decode: pdf_objects_1.PDFArray.fromArray([pdf_objects_1.PDFNumber.fromNumber(0), pdf_objects_1.PDFNumber.fromNumber(1)], _this.document.index),
Length: pdf_objects_1.PDFNumber.fromNumber(deflatedAlphaChannel.length),
}, _this.document.index);
var smaskStream = _this.document.register(pdf_objects_1.PDFRawStream.from(alphaStreamDict, deflatedAlphaChannel));
_this.xObjDict.set('SMask', smaskStream);
}
_this.xObjDict.set('Length', pdf_objects_1.PDFNumber.fromNumber(_this.imgData.length));
var xObj = _this.document.register(pdf_objects_1.PDFRawStream.from(_this.xObjDict, _this.imgData));
return xObj;
};
/** @hidden */
this.splitAlphaChannel = function () {
var pixels = _this.image.decodePixels();
var colorByteSize = (_this.image.colors * _this.image.bits) / 8;
var pixelCount = _this.image.width * _this.image.height;
_this.imgData = new Uint8Array(pixelCount * colorByteSize);
_this.alphaChannel = new Uint8Array(pixelCount);
var i = 0;
var p = 0;
var a = 0;
while (i < pixels.length) {
_this.imgData[p++] = pixels[i++];
_this.imgData[p++] = pixels[i++];
_this.imgData[p++] = pixels[i++];
_this.alphaChannel[a++] = pixels[i++];
}
_this.imgData = pako_1.default.deflate(_this.imgData);
return _this.finalize();
};
/** @hidden */
this.loadIndexedAlphaChannel = function () {
var transparency = _this.image.transparency.indexed;
var pixels = _this.image.decodePixels();
_this.alphaChannel = new Uint8Array(_this.width * _this.height);
// Can't use forEach here, because it's missing on React Native Android
for (var idx = 0; idx < pixels.length; idx++) {
_this.alphaChannel[idx] = transparency[pixels[idx]];
}
return _this.finalize();
};
validate_1.validate(data, validate_1.isInstance(Uint8Array), '"data" must be an instance of Uint8Array');
this.image = png_ts_1.default.load(data);
this.width = this.image.width;
this.height = this.image.height;
this.imgData = this.image.imgData;
}
PNGXObjectFactory.for = function (data) { return new PNGXObjectFactory(data); };
return PNGXObjectFactory;
}());
exports.default = PNGXObjectFactory;
;