@@ -496,37 +496,54 @@ def _make_image(self, A, in_bbox, out_bbox, clip_bbox, magnification=1.0,
496
496
out_alpha *= _resample (self , alpha , out_shape , t , resample = True )
497
497
# mask and run through the norm
498
498
resampled_masked = np .ma .masked_array (A_resampled , out_mask )
499
- output = self .norm (resampled_masked )
499
+ res = self .norm (resampled_masked )
500
500
else :
501
501
if A .ndim == 2 : # interpolation_stage = 'rgba'
502
502
self .norm .autoscale_None (A )
503
503
A = self .to_rgba (A )
504
504
alpha = self .get_alpha ()
505
+ post_apply_alpha = False
505
506
if alpha is None : # alpha parameter not specified
506
507
if A .shape [2 ] == 3 : # image has no alpha channel
507
- output_alpha = 255 if A .dtype == np .uint8 else 1.0
508
- else :
509
- output_alpha = _resample ( # resample alpha channel
510
- self , A [..., 3 ], out_shape , t )
511
- output = _resample ( # resample rgb channels
512
- self , _rgb_to_rgba (A [..., :3 ]), out_shape , t )
508
+ alpha = np .uint8 (0xff ) if A .dtype == np .uint8 else 1.0
509
+ A = np .dstack ([A , np .full (A .shape [:2 ], alpha )])
513
510
elif np .ndim (alpha ) > 0 : # Array alpha
514
511
# user-specified array alpha overrides the existing alpha channel
515
- output_alpha = _resample (self , alpha , out_shape , t )
516
- output = _resample (
517
- self , _rgb_to_rgba (A [..., :3 ]), out_shape , t )
512
+ A = np .dstack ([A [..., :3 ], alpha ])
518
513
else : # Scalar alpha
519
514
if A .shape [2 ] == 3 : # broadcast scalar alpha
520
- output_alpha = (255 * alpha ) if A .dtype == np .uint8 else alpha
515
+ if A .dtype == np .uint8 :
516
+ alpha = np .uint8 (0xff * alpha )
517
+ A = np .dstack ([A , np .full (A .shape [:2 ], alpha )])
521
518
else : # or apply scalar alpha to existing alpha channel
522
- output_alpha = _resample (self , A [..., 3 ], out_shape , t ) * alpha
523
- output = _resample (
524
- self , _rgb_to_rgba (A [..., :3 ]), out_shape , t )
525
- output [..., 3 ] = output_alpha # recombine rgb and alpha
526
-
527
- # output is now either a 2D array of normed (int or float) data
519
+ post_apply_alpha = True
520
+ # Resample in premultiplied alpha space. (TODO: Consider
521
+ # implementing premultiplied-space resampling in
522
+ # span_image_resample_rgba_affine::generate?)
523
+ if A .dtype == np .uint8 :
524
+ # Temporarily increase bitdepth to avoid precision loss.
525
+ A = A .astype (np .uint16 )
526
+ A [..., :3 ] *= A [..., 3 :]
527
+ A [..., 3 ] *= np .uint16 (0x100 )
528
+ res = _resample (self , A , out_shape , t )
529
+ out_alpha = res [..., 3 :] / 0x100
530
+ rgb_pre = res [..., :3 ]
531
+ rgb = rgb_pre / np .where (out_alpha , out_alpha , 1 )
532
+ res = np .dstack ([rgb , out_alpha ])
533
+ if post_apply_alpha :
534
+ res [..., 3 ] *= alpha
535
+ res = np .minimum (res .round (), 0xff ).astype (np .uint8 )
536
+ else :
537
+ A [..., :3 ] *= A [..., 3 :]
538
+ res = _resample (self , A , out_shape , t )
539
+ np .divide (res [..., :3 ], res [..., 3 :], out = res [..., :3 ],
540
+ where = res [..., 3 :] != 0 )
541
+ if post_apply_alpha :
542
+ res [..., 3 ] *= alpha
543
+
544
+ # res is now either a 2D array of normed (int or float) data
528
545
# or an RGBA array of re-sampled input
529
- output = self .to_rgba (output , bytes = True , norm = False )
546
+ output = self .to_rgba (res , bytes = True , norm = False )
530
547
# output is now a correctly sized RGBA array of uint8
531
548
532
549
# Apply alpha *after* if the input was greyscale without a mask
0 commit comments