@@ -377,6 +377,78 @@ class CachedCanvases {
377
377
}
378
378
}
379
379
380
+ function drawImageAtIntegerCoords (
381
+ ctx ,
382
+ srcImg ,
383
+ srcX ,
384
+ srcY ,
385
+ srcW ,
386
+ srcH ,
387
+ destX ,
388
+ destY ,
389
+ destW ,
390
+ destH
391
+ ) {
392
+ const [ a , b , c , d , tx , ty ] = ctx . mozCurrentTransform ;
393
+ if ( b === 0 && c === 0 ) {
394
+ // top-left corner is at (X, Y) and
395
+ // bottom-right one is at (X + width, Y + height).
396
+
397
+ // If leftX is 4.321 then it's rounded to 4.
398
+ // If width is 10.432 then it's rounded to 11 because
399
+ // rightX = leftX + width = 14.753 which is rounded to 15
400
+ // so after rounding the total width is 11 (15 - 4).
401
+ // It's why we can't just floor/ceil uniformly, it just depends
402
+ // on the values we've.
403
+
404
+ const tlX = destX * a + tx ;
405
+ const rTlX = Math . round ( tlX ) ;
406
+ const tlY = destY * d + ty ;
407
+ const rTlY = Math . round ( tlY ) ;
408
+ const brX = ( destX + destW ) * a + tx ;
409
+
410
+ // Some pdf contains images with 1x1 images so in case of 0-width after
411
+ // scaling we must fallback on 1 to be sure there is something.
412
+ const rWidth = Math . abs ( Math . round ( brX ) - rTlX ) || 1 ;
413
+ const brY = ( destY + destH ) * d + ty ;
414
+ const rHeight = Math . abs ( Math . round ( brY ) - rTlY ) || 1 ;
415
+
416
+ // We must apply a transformation in order to apply it on the image itself.
417
+ // For example if a == 1 && d == -1, it means that the image itself is
418
+ // mirrored w.r.t. the x-axis.
419
+ ctx . setTransform ( Math . sign ( a ) , 0 , 0 , Math . sign ( d ) , rTlX , rTlY ) ;
420
+ ctx . drawImage ( srcImg , srcX , srcY , srcW , srcH , 0 , 0 , rWidth , rHeight ) ;
421
+ ctx . setTransform ( a , b , c , d , tx , ty ) ;
422
+
423
+ return [ rWidth , rHeight ] ;
424
+ }
425
+
426
+ if ( a === 0 && d === 0 ) {
427
+ // This path is taken in issue9462.pdf (page 3).
428
+ const tlX = destY * c + tx ;
429
+ const rTlX = Math . round ( tlX ) ;
430
+ const tlY = destX * b + ty ;
431
+ const rTlY = Math . round ( tlY ) ;
432
+ const brX = ( destY + destH ) * c + tx ;
433
+ const rWidth = Math . abs ( Math . round ( brX ) - rTlX ) || 1 ;
434
+ const brY = ( destX + destW ) * b + ty ;
435
+ const rHeight = Math . abs ( Math . round ( brY ) - rTlY ) || 1 ;
436
+
437
+ ctx . setTransform ( 0 , Math . sign ( b ) , Math . sign ( c ) , 0 , rTlX , rTlY ) ;
438
+ ctx . drawImage ( srcImg , srcX , srcY , srcW , srcH , 0 , 0 , rHeight , rWidth ) ;
439
+ ctx . setTransform ( a , b , c , d , tx , ty ) ;
440
+
441
+ return [ rHeight , rWidth ] ;
442
+ }
443
+
444
+ // Not a scale matrix so let the render handle the case without rounding.
445
+ ctx . drawImage ( srcImg , srcX , srcY , srcW , srcH , destX , destY , destW , destH ) ;
446
+
447
+ const scaleX = Math . hypot ( a , b ) ;
448
+ const scaleY = Math . hypot ( c , d ) ;
449
+ return [ scaleX * destW , scaleY * destH ] ;
450
+ }
451
+
380
452
function compileType3Glyph ( imgData ) {
381
453
const POINT_TO_PROCESS_LIMIT = 1000 ;
382
454
const POINT_TYPES = new Uint8Array ( [
@@ -1461,8 +1533,8 @@ class CanvasGraphics {
1461
1533
const cord1 = Util . applyTransform ( [ 0 , 0 ] , maskToCanvas ) ;
1462
1534
const cord2 = Util . applyTransform ( [ width , height ] , maskToCanvas ) ;
1463
1535
const rect = Util . normalizeRect ( [ cord1 [ 0 ] , cord1 [ 1 ] , cord2 [ 0 ] , cord2 [ 1 ] ] ) ;
1464
- const drawnWidth = Math . ceil ( rect [ 2 ] - rect [ 0 ] ) ;
1465
- const drawnHeight = Math . ceil ( rect [ 3 ] - rect [ 1 ] ) ;
1536
+ const drawnWidth = Math . round ( rect [ 2 ] - rect [ 0 ] ) || 1 ;
1537
+ const drawnHeight = Math . round ( rect [ 3 ] - rect [ 1 ] ) || 1 ;
1466
1538
const fillCanvas = this . cachedCanvases . getCanvas (
1467
1539
"fillCanvas" ,
1468
1540
drawnWidth ,
@@ -1496,7 +1568,9 @@ class CanvasGraphics {
1496
1568
fillCtx . mozCurrentTransform ,
1497
1569
img . interpolate
1498
1570
) ;
1499
- fillCtx . drawImage (
1571
+
1572
+ drawImageAtIntegerCoords (
1573
+ fillCtx ,
1500
1574
scaled ,
1501
1575
0 ,
1502
1576
0 ,
@@ -3005,7 +3079,18 @@ class CanvasGraphics {
3005
3079
ctx . save ( ) ;
3006
3080
ctx . transform . apply ( ctx , image . transform ) ;
3007
3081
ctx . scale ( 1 , - 1 ) ;
3008
- ctx . drawImage ( maskCanvas . canvas , 0 , 0 , width , height , 0 , - 1 , 1 , 1 ) ;
3082
+ drawImageAtIntegerCoords (
3083
+ ctx ,
3084
+ maskCanvas . canvas ,
3085
+ 0 ,
3086
+ 0 ,
3087
+ width ,
3088
+ height ,
3089
+ 0 ,
3090
+ - 1 ,
3091
+ 1 ,
3092
+ 1
3093
+ ) ;
3009
3094
ctx . restore ( ) ;
3010
3095
}
3011
3096
this . compose ( ) ;
@@ -3085,7 +3170,9 @@ class CanvasGraphics {
3085
3170
ctx . mozCurrentTransform ,
3086
3171
imgData . interpolate
3087
3172
) ;
3088
- ctx . drawImage (
3173
+
3174
+ const [ rWidth , rHeight ] = drawImageAtIntegerCoords (
3175
+ ctx ,
3089
3176
scaled . img ,
3090
3177
0 ,
3091
3178
0 ,
@@ -3103,8 +3190,8 @@ class CanvasGraphics {
3103
3190
imgData,
3104
3191
left : position [ 0 ] ,
3105
3192
top : position [ 1 ] ,
3106
- width : width / ctx . mozCurrentTransformInverse [ 0 ] ,
3107
- height : height / ctx . mozCurrentTransformInverse [ 3 ] ,
3193
+ width : rWidth ,
3194
+ height : rHeight ,
3108
3195
} ) ;
3109
3196
}
3110
3197
this . compose ( ) ;
@@ -3133,7 +3220,8 @@ class CanvasGraphics {
3133
3220
ctx . save ( ) ;
3134
3221
ctx . transform . apply ( ctx , entry . transform ) ;
3135
3222
ctx . scale ( 1 , - 1 ) ;
3136
- ctx . drawImage (
3223
+ drawImageAtIntegerCoords (
3224
+ ctx ,
3137
3225
tmpCanvas . canvas ,
3138
3226
entry . x ,
3139
3227
entry . y ,
0 commit comments