@@ -409,14 +409,19 @@ function apply(kind: Kind, linear: boolean, ts: Matrix, region: Rect, subregion:
409409 case 'displacement' : {
410410 const src = inColorSpace ( input ( kind . input ) , linear ) . pixmap , map = inColorSpace ( input ( kind . input2 ) , linear ) . pixmap ;
411411 const pixmap = create ( region . width , region . height ) ;
412- // (like resvg: the scale counts twice, the map isn't unpremultiplied)
412+ // (the scale once, like the specification and browsers: resvg multiplies by it twice, moving everything out
413+ // of the region at the scales SVGs use; the map's colors unpremultiplied, as the specification says)
413414 const sx = kind . scale * scaleX , sy = kind . scale * scaleY , w = src . width , h = src . height ;
414415 const round = ( v : number ) : number => Math . sign ( v ) * Math . round ( Math . abs ( v ) ) ;
416+ const channel = ( m : number , c : number ) : number => {
417+ const a = map . data [ m + 3 ] ;
418+ return c === 3 ? a / 255 : a ? map . data [ m + c ] / a : 0 ;
419+ } ;
415420 for ( let y = 0 ; y < Math . min ( h , map . height ) ; y ++ )
416421 for ( let x = 0 ; x < Math . min ( w , map . width ) ; x ++ ) {
417422 const m = ( y * map . width + x ) * 4 ;
418- const ox = round ( x + ( map . data [ m + kind . xChannel ] / 255 - 0.5 ) * sx * kind . scale ) ;
419- const oy = round ( y + ( map . data [ m + kind . yChannel ] / 255 - 0.5 ) * sy * kind . scale ) ;
423+ const ox = round ( x + ( channel ( m , kind . xChannel ) - 0.5 ) * sx ) ;
424+ const oy = round ( y + ( channel ( m , kind . yChannel ) - 0.5 ) * sy ) ;
420425 if ( ox < 0 || ox >= w || oy < 0 || oy >= h ) continue ;
421426 pixmap . data . set ( src . data . subarray ( ( oy * w + ox ) * 4 , ( oy * w + ox ) * 4 + 4 ) , ( y * pixmap . width + x ) * 4 ) ;
422427 }
0 commit comments