@@ -875,7 +875,7 @@ def test_decode_gif_webp_errors(decode_fun):
875875 if decode_fun is decode_gif :
876876 expected_match = re .escape ("DGifOpenFileName() failed - 103" )
877877 elif decode_fun is decode_webp :
878- expected_match = "WebPDecodeRGB failed."
878+ expected_match = "WebPGetFeatures failed."
879879 with pytest .raises (RuntimeError , match = expected_match ):
880880 decode_fun (encoded_data )
881881
@@ -891,6 +891,31 @@ def test_decode_webp(decode_fun, scripted):
891891 assert img [None ].is_contiguous (memory_format = torch .channels_last )
892892
893893
894+ # This test is skipped because it requires webp images that we're not including
895+ # within the repo. The test images were downloaded from the different pages of
896+ # https://developers.google.com/speed/webp/gallery
897+ # Note that converting an RGBA image to RGB leads to bad results because the
898+ # transparent pixels aren't necessarily set to "black" or "white", they can be
899+ # random stuff. This is consistent with PIL results.
900+ @pytest .mark .skip (reason = "Need to download test images first" )
901+ @pytest .mark .parametrize ("decode_fun" , (decode_webp , decode_image ))
902+ @pytest .mark .parametrize ("scripted" , (False , True ))
903+ @pytest .mark .parametrize (
904+ "mode, pil_mode" , ((ImageReadMode .RGB , "RGB" ), (ImageReadMode .RGB_ALPHA , "RGBA" ), (ImageReadMode .UNCHANGED , None ))
905+ )
906+ @pytest .mark .parametrize ("filename" , Path ("/home/nicolashug/webp_samples" ).glob ("*.webp" ))
907+ def test_decode_webp_against_pil (decode_fun , scripted , mode , pil_mode , filename ):
908+ encoded_bytes = read_file (filename )
909+ if scripted :
910+ decode_fun = torch .jit .script (decode_fun )
911+ img = decode_fun (encoded_bytes , mode = mode )
912+ assert img [None ].is_contiguous (memory_format = torch .channels_last )
913+
914+ pil_img = Image .open (filename ).convert (pil_mode )
915+ from_pil = F .pil_to_tensor (pil_img )
916+ assert_equal (img , from_pil )
917+
918+
894919@pytest .mark .xfail (reason = "AVIF support not enabled yet." )
895920@pytest .mark .parametrize ("decode_fun" , (_decode_avif , decode_image ))
896921@pytest .mark .parametrize ("scripted" , (False , True ))
@@ -903,5 +928,65 @@ def test_decode_avif(decode_fun, scripted):
903928 assert img [None ].is_contiguous (memory_format = torch .channels_last )
904929
905930
931+ @pytest .mark .xfail (reason = "AVIF support not enabled yet." )
932+ # Note: decode_image fails because some of these files have a (valid) signature
933+ # we don't recognize. We should probably use libmagic....
934+ # @pytest.mark.parametrize("decode_fun", (_decode_avif, decode_image))
935+ @pytest .mark .parametrize ("decode_fun" , (_decode_avif ,))
936+ @pytest .mark .parametrize ("scripted" , (False , True ))
937+ @pytest .mark .parametrize (
938+ "mode, pil_mode" ,
939+ (
940+ (ImageReadMode .RGB , "RGB" ),
941+ (ImageReadMode .RGB_ALPHA , "RGBA" ),
942+ (ImageReadMode .UNCHANGED , None ),
943+ ),
944+ )
945+ @pytest .mark .parametrize ("filename" , Path ("/home/nicolashug/dev/libavif/tests/data/" ).glob ("*.avif" ))
946+ def test_decode_avif_against_pil (decode_fun , scripted , mode , pil_mode , filename ):
947+ if "reversed_dimg_order" in str (filename ):
948+ # Pillow properly decodes this one, but we don't (order of parts of the
949+ # image is wrong). This is due to a bug that was recently fixed in
950+ # libavif. Hopefully this test will end up passing soon with a new
951+ # libavif version https://github.com/AOMediaCodec/libavif/issues/2311
952+ pytest .xfail ()
953+ import pillow_avif # noqa
954+
955+ encoded_bytes = read_file (filename )
956+ if scripted :
957+ decode_fun = torch .jit .script (decode_fun )
958+ try :
959+ img = decode_fun (encoded_bytes , mode = mode )
960+ except RuntimeError as e :
961+ if any (
962+ s in str (e )
963+ for s in ("BMFF parsing failed" , "avifDecoderParse failed: " , "file contains more than one image" )
964+ ):
965+ pytest .skip (reason = "Expected failure, that's OK" )
966+ else :
967+ raise e
968+ assert img [None ].is_contiguous (memory_format = torch .channels_last )
969+ if mode == ImageReadMode .RGB :
970+ assert img .shape [0 ] == 3
971+ if mode == ImageReadMode .RGB_ALPHA :
972+ assert img .shape [0 ] == 4
973+ if img .dtype == torch .uint16 :
974+ img = F .to_dtype (img , dtype = torch .uint8 , scale = True )
975+
976+ from_pil = F .pil_to_tensor (Image .open (filename ).convert (pil_mode ))
977+ if False :
978+ from torchvision .utils import make_grid
979+
980+ g = make_grid ([img , from_pil ])
981+ F .to_pil_image (g ).save ((f"/home/nicolashug/out_images/{ filename .name } .{ pil_mode } .png" ))
982+ if mode != ImageReadMode .RGB :
983+ # We don't compare against PIL for RGB because results look pretty
984+ # different on RGBA images (other images are fine). The result on
985+ # torchvision basically just plainly ignores the alpha channel, resuting
986+ # in transparent pixels looking dark. PIL seems to be using a sort of
987+ # k-nn thing, looking at the output. Take a look at the resuting images.
988+ torch .testing .assert_close (img , from_pil , rtol = 0 , atol = 3 )
989+
990+
906991if __name__ == "__main__" :
907992 pytest .main ([__file__ ])
0 commit comments