UNPKG

pdf-lib

Version:

Library for creating and modifying PDF files in JavaScript

123 lines (122 loc) 6.73 kB
"use strict"; 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;