@@ -260,15 +260,28 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
260
260
return ;
261
261
}
262
262
263
+ var softMask = dict .get ('SMask' , 'SM' ) || false ;
264
+ var mask = dict .get ('Mask' ) || false ;
265
+
266
+ var SMALL_IMAGE_DIMENSIONS = 200 ;
267
+ // Inlining small images into the queue as RGB data
268
+ if (inline && !softMask && !mask &&
269
+ !(image instanceof JpegStream ) &&
270
+ (w + h ) < SMALL_IMAGE_DIMENSIONS ) {
271
+ var imageObj = new PDFImage (xref , resources , image ,
272
+ inline , null , null );
273
+ var imgData = imageObj .getImageData ();
274
+ fn = 'paintInlineImageXObject' ;
275
+ args = [imgData ];
276
+ return ;
277
+ }
278
+
263
279
// If there is no imageMask, create the PDFImage and a lot
264
280
// of image processing can be done here.
265
281
var objId = 'img_' + uniquePrefix + (++self .objIdCounter );
266
282
insertDependency ( [objId ]);
267
283
args = [objId , w , h ];
268
284
269
- var softMask = dict .get ('SMask' , 'SM' ) || false ;
270
- var mask = dict .get ('Mask' ) || false ;
271
-
272
285
if (!softMask && !mask && image instanceof JpegStream &&
273
286
image .isNativelySupported (xref , resources )) {
274
287
// These JPEGs don't need any more processing so we can just send it.
@@ -280,15 +293,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
280
293
fn = 'paintImageXObject' ;
281
294
282
295
PDFImage .buildImage (function (imageObj ) {
283
- var drawWidth = imageObj .drawWidth ;
284
- var drawHeight = imageObj .drawHeight ;
285
- var imgData = {
286
- width : drawWidth ,
287
- height : drawHeight ,
288
- data : new Uint8Array (drawWidth * drawHeight * 4 )
289
- };
290
- var pixels = imgData .data ;
291
- imageObj .fillRgbaBuffer (pixels , drawWidth , drawHeight );
296
+ var imgData = imageObj .getImageData ();
292
297
handler .send ('obj' , [objId , pageIndex , 'Image' , imgData ]);
293
298
}, handler , xref , resources , image , inline );
294
299
}
@@ -512,6 +517,122 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
512
517
return queue ;
513
518
},
514
519
520
+ optimizeQueue : function PartialEvaluator_optimizeQueue (queue ) {
521
+ var fnArray = queue .fnArray , argsArray = queue .argsArray ;
522
+ // grouping paintInlineImageXObject's into paintInlineImageXObjectGroup
523
+ // searching for (save, transform, paintInlineImageXObject, restore)+
524
+ var MIN_IMAGES_IN_INLINE_IMAGES_BLOCK = 10 ;
525
+ var MAX_IMAGES_IN_INLINE_IMAGES_BLOCK = 200 ;
526
+ var MAX_WIDTH = 1000 ;
527
+ var IMAGE_PADDING = 1 ;
528
+ for (var i = 0 , ii = fnArray .length ; i < ii ; i ++) {
529
+ if (fnArray [i ] === 'paintInlineImageXObject' &&
530
+ fnArray [i - 2 ] === 'save' && fnArray [i - 1 ] === 'transform' &&
531
+ fnArray [i + 1 ] === 'restore' ) {
532
+ var j = i - 2 ;
533
+ for (i += 2 ; i < ii && fnArray [i - 4 ] === fnArray [i ]; i ++) {
534
+ }
535
+ var count = Math .min ((i - j ) >> 2 ,
536
+ MAX_IMAGES_IN_INLINE_IMAGES_BLOCK );
537
+ if (count < MIN_IMAGES_IN_INLINE_IMAGES_BLOCK ) {
538
+ continue ;
539
+ }
540
+ // assuming that heights of those image is too small (~1 pixel)
541
+ // packing as much as possible by lines
542
+ var maxX = 0 ;
543
+ var map = [], maxLineHeight = 0 ;
544
+ var currentX = IMAGE_PADDING , currentY = IMAGE_PADDING ;
545
+ for (var q = 0 ; q < count ; q ++) {
546
+ var transform = argsArray [j + (q << 2 ) + 1 ];
547
+ var img = argsArray [j + (q << 2 ) + 2 ][0 ];
548
+ if (currentX + img .width > MAX_WIDTH ) {
549
+ // starting new line
550
+ maxX = Math .max (maxX , currentX );
551
+ currentY += maxLineHeight + 2 * IMAGE_PADDING ;
552
+ currentX = 0 ;
553
+ maxLineHeight = 0 ;
554
+ }
555
+ map .push ({
556
+ transform : transform ,
557
+ x : currentX , y : currentY ,
558
+ w : img .width , h : img .height
559
+ });
560
+ currentX += img .width + 2 * IMAGE_PADDING ;
561
+ maxLineHeight = Math .max (maxLineHeight , img .height );
562
+ }
563
+ var imgWidth = Math .max (maxX , currentX ) + IMAGE_PADDING ;
564
+ var imgHeight = currentY + maxLineHeight + IMAGE_PADDING ;
565
+ var imgData = new Uint8Array (imgWidth * imgHeight * 4 );
566
+ var imgRowSize = imgWidth << 2 ;
567
+ for (var q = 0 ; q < count ; q ++) {
568
+ var data = argsArray [j + (q << 2 ) + 2 ][0 ].data ;
569
+ // copy image by lines and extends pixels into padding
570
+ var rowSize = map [q ].w << 2 ;
571
+ var dataOffset = 0 ;
572
+ var offset = (map [q ].x + map [q ].y * imgWidth ) << 2 ;
573
+ imgData .set (
574
+ data .subarray (0 , rowSize ), offset - imgRowSize );
575
+ for (var k = 0 , kk = map [q ].h ; k < kk ; k ++) {
576
+ imgData .set (
577
+ data .subarray (dataOffset , dataOffset + rowSize ), offset );
578
+ dataOffset += rowSize ;
579
+ offset += imgRowSize ;
580
+ }
581
+ imgData .set (
582
+ data .subarray (dataOffset - rowSize , dataOffset ), offset );
583
+ while (offset >= 0 ) {
584
+ data [offset - 4 ] = data [offset ];
585
+ data [offset - 3 ] = data [offset + 1 ];
586
+ data [offset - 2 ] = data [offset + 2 ];
587
+ data [offset - 1 ] = data [offset + 3 ];
588
+ data [offset + rowSize ] = data [offset + rowSize - 4 ];
589
+ data [offset + rowSize + 1 ] = data [offset + rowSize - 3 ];
590
+ data [offset + rowSize + 2 ] = data [offset + rowSize - 2 ];
591
+ data [offset + rowSize + 3 ] = data [offset + rowSize - 1 ];
592
+ offset -= imgRowSize ;
593
+ }
594
+ }
595
+ // replacing queue items
596
+ fnArray .splice (j , count * 4 , ['paintInlineImageXObjectGroup' ]);
597
+ argsArray .splice (j , count * 4 ,
598
+ [{width : imgWidth , height : imgHeight , data : imgData }, map ]);
599
+ i = j ;
600
+ ii = fnArray .length ;
601
+ }
602
+ }
603
+ // grouping paintImageMaskXObject's into paintImageMaskXObjectGroup
604
+ // searching for (save, transform, paintImageMaskXObject, restore)+
605
+ var MIN_IMAGES_IN_MASKS_BLOCK = 10 ;
606
+ var MAX_IMAGES_IN_MASKS_BLOCK = 100 ;
607
+ for (var i = 0 , ii = fnArray .length ; i < ii ; i ++) {
608
+ if (fnArray [i ] === 'paintImageMaskXObject' &&
609
+ fnArray [i - 2 ] === 'save' && fnArray [i - 1 ] === 'transform' &&
610
+ fnArray [i + 1 ] === 'restore' ) {
611
+ var j = i - 2 ;
612
+ for (i += 2 ; i < ii && fnArray [i - 4 ] === fnArray [i ]; i ++) {
613
+ }
614
+ var count = Math .min ((i - j ) >> 2 ,
615
+ MAX_IMAGES_IN_MASKS_BLOCK );
616
+ if (count < MIN_IMAGES_IN_MASKS_BLOCK ) {
617
+ continue ;
618
+ }
619
+ var images = [];
620
+ for (var q = 0 ; q < count ; q ++) {
621
+ var transform = argsArray [j + (q << 2 ) + 1 ];
622
+ var maskParams = argsArray [j + (q << 2 ) + 2 ];
623
+ images .push ({data : maskParams [0 ], width : maskParams [2 ],
624
+ height : maskParams [3 ], transform : transform ,
625
+ inverseDecode : maskParams [1 ]});
626
+ }
627
+ // replacing queue items
628
+ fnArray .splice (j , count * 4 , ['paintImageMaskXObjectGroup' ]);
629
+ argsArray .splice (j , count * 4 , [images ]);
630
+ i = j ;
631
+ ii = fnArray .length ;
632
+ }
633
+ }
634
+ },
635
+
515
636
getTextContent : function PartialEvaluator_getTextContent (
516
637
stream , resources , state ) {
517
638
var bidiTexts ;
0 commit comments