Skip to content
This repository was archived by the owner on Apr 12, 2021. It is now read-only.

Commit 0ef714f

Browse files
author
Duncan MacKenzie
committed
Add support for GIF images
1 parent 397ca97 commit 0ef714f

File tree

9 files changed

+95
-25
lines changed

9 files changed

+95
-25
lines changed

lib/image.js

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,10 @@ By Devon Govett
66
import fs from 'fs'
77
import JPEG from './image/jpeg'
88
import PNG from './image/png'
9+
import GIF from './image/gif'
910

1011
class PDFImage {
11-
static open(src, label) {
12+
static open(src, label, options) {
1213
let data
1314
if (Buffer.isBuffer(src)) {
1415
data = src
@@ -27,9 +28,11 @@ class PDFImage {
2728
}
2829

2930
if (data[0] === 0xff && data[1] === 0xd8) {
30-
return new JPEG(data, label)
31+
return new JPEG(data, label, options)
3132
} else if (data[0] === 0x89 && data.toString('ascii', 1, 4) === 'PNG') {
32-
return new PNG(data, label)
33+
return new PNG(data, label, options)
34+
} else if (data[0] === 71 && data[1] === 73 && data[2] === 70) {
35+
return new GIF(data, label, options)
3336
} else {
3437
throw new Error('Unknown image format.')
3538
}

lib/image/gif.js

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import GIFuct from './gifuct-js';
2+
3+
const COLOR_SPACE_MAP = {
4+
1: 'DeviceGray',
5+
3: 'DeviceRGB',
6+
4: 'DeviceCMYK'
7+
}
8+
class GIF {
9+
constructor(data, label, { width, height } = {}) {
10+
this.data = data;
11+
this.label = label;
12+
13+
// validate data integrity
14+
15+
// assign bits per component to this.bits
16+
this.bits = 8;
17+
18+
// assign image width and height to this.width and this.height
19+
this.width = width || 0;
20+
this.height = height || 0;
21+
22+
this.colorSpace = COLOR_SPACE_MAP[3];
23+
24+
this.obj = null;
25+
}
26+
27+
embed(document) {
28+
if (this.obj) { return; }
29+
30+
const gif = new GIFuct(this.data);
31+
const data = gif.getFrame(0, false, false);
32+
console.log('Data from GIFuct:', data);
33+
34+
this.obj = document.ref({
35+
Type: 'XObject',
36+
Subtype: 'Image',
37+
BitsPerComponent: this.bits,
38+
Width: this.width,
39+
Height: this.height,
40+
ColorSpace: this.colorSpace,
41+
Filter: data.format === 'lzw' ? 'LZWDecode' : 'FlateDecode',
42+
});
43+
44+
this.obj.end(data);
45+
46+
// free memory
47+
return this.data = null;
48+
}
49+
};
50+
51+
export default GIF;

lib/image/gifuct-js/src/gif.js

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
1+
/* eslint-disable */
22
// object used to represent array buffer data for a gif file
33

4-
var DataParser = require('../node_modules/js-binary-schema-parser/src/dataparser');
5-
var gifSchema = require('./schema');
4+
import DataParser from '../../js-binary-schema-parser/src/dataparser';
5+
import gifSchema from './schema';
66

77
function GIF(arrayBuffer){
88
// convert to byte array
@@ -25,32 +25,48 @@ function GIF(arrayBuffer){
2525
// if buildPatch is true, the returned image will be a clamped 8 bit image patch
2626
// for use directly with a canvas.
2727
GIF.prototype.decompressFrame = function(index, buildPatch){
28+
return this.getFrame(index, buildPatch, true);
29+
}
30+
31+
// set decompress to false to retrieve the LZW-compressed image data
32+
GIF.prototype.getFrame = function(index, buildPatch, decompress){
2833

2934
// make sure a valid frame is requested
3035
if(index >= this.raw.frames.length){ return null; }
3136

3237
var frame = this.raw.frames[index];
33-
if(frame.image){
38+
if (frame.image) {
39+
var isInterlaced = frame.image.descriptor.lct.interlaced;
40+
3441
// get the number of pixels
3542
var totalPixels = frame.image.descriptor.width * frame.image.descriptor.height;
43+
var pixels;
3644

3745
// do lzw decompression
38-
var pixels = lzw(frame.image.data.minCodeSize, frame.image.data.blocks, totalPixels);
46+
if (decompress !== false || buildPatch || isInterlaced) {
47+
pixels = lzw(frame.image.data.minCodeSize, frame.image.data.blocks, totalPixels);
48+
}
3949

4050
// deal with interlacing if necessary
41-
if(frame.image.descriptor.lct.interlaced){
51+
if (isInterlaced) {
4252
pixels = deinterlace(pixels, frame.image.descriptor.width);
4353
}
4454

55+
if (!pixels) {
56+
console.log('Returning image data:', frame.image.data.blocks);
57+
}
58+
4559
// setup usable image object
4660
var image = {
61+
data: !pixels ? frame.image.data.blocks : undefined,
4762
pixels: pixels,
4863
dims: {
4964
top: frame.image.descriptor.top,
5065
left: frame.image.descriptor.left,
5166
width: frame.image.descriptor.width,
5267
height: frame.image.descriptor.height
53-
}
68+
},
69+
format: pixels ? 'raw' : 'lzw'
5470
};
5571

5672
// color table
@@ -80,6 +96,7 @@ GIF.prototype.decompressFrame = function(index, buildPatch){
8096

8197
// frame does not contains image
8298
return null;
99+
};
83100

84101

85102
/**
@@ -230,7 +247,6 @@ GIF.prototype.decompressFrame = function(index, buildPatch){
230247

231248
return patchData;
232249
}
233-
};
234250

235251
// returns all frames decompressed
236252
GIF.prototype.decompressFrames = function(buildPatch){
@@ -244,4 +260,4 @@ GIF.prototype.decompressFrames = function(buildPatch){
244260
return frames;
245261
};
246262

247-
module.exports = GIF;
263+
export default GIF;

lib/image/gifuct-js/src/schema.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
1+
/* eslint-disable */
22
// Schema for the js file parser to use to parse gif files
33
// For js object convenience (re-use), the schema objects are approximately reverse ordered
44

55
// common parsers available
6-
var Parsers = require('../node_modules/js-binary-schema-parser/src/parsers');
6+
import Parsers from '../../js-binary-schema-parser/src/parsers';
77

88
// a set of 0x00 terminated subblocks
99
var subBlocks = {
@@ -202,4 +202,4 @@ var schemaGIF = [
202202
frames // content frames
203203
];
204204

205-
module.exports = schemaGIF;
205+
export default schemaGIF;

lib/image/js-binary-schema-parser/src/bytestream.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,4 +55,4 @@ ByteStream.prototype.readUnsigned = function(littleEndian){
5555
}
5656
};
5757

58-
module.exports = ByteStream;
58+
export default ByteStream;

lib/image/js-binary-schema-parser/src/dataparser.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11

22
// Primary data parsing object used to parse byte arrays
33

4-
var ByteStream = require('./bytestream');
4+
import ByteStream from './bytestream';
55

66
function DataParser(data){
77
this.stream = new ByteStream(data);
@@ -79,4 +79,4 @@ DataParser.prototype.parseBits = function(details){
7979
return out;
8080
};
8181

82-
module.exports = DataParser;
82+
export default DataParser;

lib/image/js-binary-schema-parser/src/parsers.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,4 +39,4 @@ var Parsers = {
3939
}
4040
};
4141

42-
module.exports = Parsers;
42+
export default Parsers;

lib/mixins/images.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ export default {
2525
if (src.width && src.height) {
2626
image = src;
2727
} else {
28-
image = this.openImage(src);
28+
image = this.openImage(src, { width: options.width, height: options.height });
2929
}
3030
}
3131

@@ -102,14 +102,14 @@ export default {
102102
return this;
103103
},
104104

105-
openImage(src) {
105+
openImage(src, options) {
106106
let image;
107107
if (typeof src === 'string') {
108108
image = this._imageRegistry[src];
109109
}
110110

111111
if (!image) {
112-
image = PDFImage.open(src, `I${++this._imageCount}`);
112+
image = PDFImage.open(src, `I${++this._imageCount}`, options);
113113
if (typeof src === 'string') {
114114
this._imageRegistry[src] = image;
115115
}

package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,20 +49,20 @@
4949
"rollup": "^0.52.2",
5050
"rollup-plugin-babel": "3",
5151
"rollup-plugin-bundle-size": "https://github.com/vimeo/rollup-plugin-bundle-size",
52+
"rollup-plugin-cpy": "^1.0.0",
5253
"rollup-plugin-ignore": "^1.0.3",
5354
"rollup-plugin-json": "^2.1.0",
5455
"rollup-plugin-node-resolve": "^2.0.0",
5556
"rollup-plugin-replace": "^1.1.1",
5657
"rollup-plugin-string": "^2.0.2",
57-
"rollup-plugin-uglify": "^3.0.0",
58-
"rollup-plugin-cpy": "^1.0.0"
58+
"rollup-plugin-uglify": "^3.0.0"
5959
},
6060
"dependencies": {
6161
"@react-pdf/fontkit": "^1.11.0",
6262
"@react-pdf/png-js": "^1.0.0",
63-
"lz-string": "^1.4.4",
6463
"crypto-js": "^3.1.9-1",
6564
"linebreak": "^0.3.0",
65+
"lz-string": "^1.4.4",
6666
"saslprep": "1.0.1"
6767
},
6868
"jest": {

0 commit comments

Comments
 (0)