4
4
import os
5
5
import re
6
6
import sys
7
- from contextlib import nullcontext
8
7
from pathlib import Path
9
8
10
9
import numpy as np
14
13
import torchvision .transforms .v2 .functional as F
15
14
from common_utils import assert_equal , cpu_and_cuda , IN_OSS_CI , needs_cuda
16
15
from PIL import __version__ as PILLOW_VERSION , Image , ImageOps , ImageSequence
17
- from torchvision ._internally_replaced_utils import IN_FBCODE
18
16
from torchvision .io .image import (
19
- _decode_avif ,
20
- _decode_heic ,
17
+ decode_avif ,
21
18
decode_gif ,
19
+ decode_heic ,
22
20
decode_image ,
23
21
decode_jpeg ,
24
22
decode_png ,
43
41
TOOSMALL_PNG = os .path .join (IMAGE_ROOT , "toosmall_png" )
44
42
IS_WINDOWS = sys .platform in ("win32" , "cygwin" )
45
43
IS_MACOS = sys .platform == "darwin"
44
+ IS_LINUX = sys .platform == "linux"
46
45
PILLOW_VERSION = tuple (int (x ) for x in PILLOW_VERSION .split ("." ))
47
46
WEBP_TEST_IMAGES_DIR = os .environ .get ("WEBP_TEST_IMAGES_DIR" , "" )
48
47
# See https://github.com/pytorch/vision/pull/8724#issuecomment-2503964558
49
- ROCM_WEBP_MESSAGE = "ROCM not built with webp support."
50
-
51
- # Hacky way of figuring out whether we compiled with libavif/libheif (those are
52
- # currenlty disabled by default)
53
- try :
54
- _decode_avif (torch .arange (10 , dtype = torch .uint8 ))
55
- except Exception as e :
56
- DECODE_AVIF_ENABLED = "torchvision not compiled with libavif support" not in str (e )
57
-
58
- try :
59
- _decode_heic (torch .arange (10 , dtype = torch .uint8 ))
60
- except Exception as e :
61
- DECODE_HEIC_ENABLED = "torchvision not compiled with libheif support" not in str (e )
48
+ HEIC_AVIF_MESSAGE = "AVIF and HEIF only available on linux."
62
49
63
50
64
51
def _get_safe_image_name (name ):
@@ -866,19 +853,23 @@ def test_decode_gif(tmpdir, name, scripted):
866
853
torch .testing .assert_close (tv_frame , pil_frame , atol = 0 , rtol = 0 )
867
854
868
855
869
- decode_fun_and_match = [
870
- (decode_png , "Content is not png" ),
871
- (decode_jpeg , "Not a JPEG file" ),
872
- (decode_gif , re .escape ("DGifOpenFileName() failed - 103" )),
873
- (decode_webp , "WebPGetFeatures failed." ),
874
- ]
875
- if DECODE_AVIF_ENABLED :
876
- decode_fun_and_match .append ((_decode_avif , "BMFF parsing failed" ))
877
- if DECODE_HEIC_ENABLED :
878
- decode_fun_and_match .append ((_decode_heic , "Invalid input: No 'ftyp' box" ))
879
-
880
-
881
- @pytest .mark .parametrize ("decode_fun, match" , decode_fun_and_match )
856
+ @pytest .mark .parametrize (
857
+ "decode_fun, match" ,
858
+ [
859
+ (decode_png , "Content is not png" ),
860
+ (decode_jpeg , "Not a JPEG file" ),
861
+ (decode_gif , re .escape ("DGifOpenFileName() failed - 103" )),
862
+ (decode_webp , "WebPGetFeatures failed." ),
863
+ pytest .param (
864
+ decode_avif , "BMFF parsing failed" , marks = pytest .mark .skipif (not IS_LINUX , reason = HEIC_AVIF_MESSAGE )
865
+ ),
866
+ pytest .param (
867
+ decode_heic ,
868
+ "Invalid input: No 'ftyp' box" ,
869
+ marks = pytest .mark .skipif (not IS_LINUX , reason = HEIC_AVIF_MESSAGE ),
870
+ ),
871
+ ],
872
+ )
882
873
def test_decode_bad_encoded_data (decode_fun , match ):
883
874
encoded_data = torch .randint (0 , 256 , (100 ,), dtype = torch .uint8 )
884
875
with pytest .raises (RuntimeError , match = "Input tensor must be 1-dimensional" ):
@@ -934,13 +925,10 @@ def test_decode_webp_against_pil(decode_fun, scripted, mode, pil_mode, filename)
934
925
img += 123 # make sure image buffer wasn't freed by underlying decoding lib
935
926
936
927
937
- @pytest .mark .skipif (not DECODE_AVIF_ENABLED , reason = "AVIF support not enabled." )
938
- @pytest .mark .parametrize ("decode_fun" , (_decode_avif , decode_image ))
939
- @pytest .mark .parametrize ("scripted" , (False , True ))
940
- def test_decode_avif (decode_fun , scripted ):
928
+ @pytest .mark .skipif (not IS_LINUX , reason = HEIC_AVIF_MESSAGE )
929
+ @pytest .mark .parametrize ("decode_fun" , (decode_avif ,))
930
+ def test_decode_avif (decode_fun ):
941
931
encoded_bytes = read_file (next (get_images (FAKEDATA_DIR , ".avif" )))
942
- if scripted :
943
- decode_fun = torch .jit .script (decode_fun )
944
932
img = decode_fun (encoded_bytes )
945
933
assert img .shape == (3 , 100 , 100 )
946
934
assert img [None ].is_contiguous (memory_format = torch .channels_last )
@@ -949,16 +937,8 @@ def test_decode_avif(decode_fun, scripted):
949
937
950
938
# Note: decode_image fails because some of these files have a (valid) signature
951
939
# we don't recognize. We should probably use libmagic....
952
- decode_funs = []
953
- if DECODE_AVIF_ENABLED :
954
- decode_funs .append (_decode_avif )
955
- if DECODE_HEIC_ENABLED :
956
- decode_funs .append (_decode_heic )
957
-
958
-
959
- @pytest .mark .skipif (not decode_funs , reason = "Built without avif and heic support." )
960
- @pytest .mark .parametrize ("decode_fun" , decode_funs )
961
- @pytest .mark .parametrize ("scripted" , (False , True ))
940
+ @pytest .mark .skipif (not IS_LINUX , reason = HEIC_AVIF_MESSAGE )
941
+ @pytest .mark .parametrize ("decode_fun" , (decode_avif , decode_heic ))
962
942
@pytest .mark .parametrize (
963
943
"mode, pil_mode" ,
964
944
(
@@ -970,7 +950,7 @@ def test_decode_avif(decode_fun, scripted):
970
950
@pytest .mark .parametrize (
971
951
"filename" , Path ("/home/nicolashug/dev/libavif/tests/data/" ).glob ("*.avif" ), ids = lambda p : p .name
972
952
)
973
- def test_decode_avif_heic_against_pil (decode_fun , scripted , mode , pil_mode , filename ):
953
+ def test_decode_avif_heic_against_pil (decode_fun , mode , pil_mode , filename ):
974
954
if "reversed_dimg_order" in str (filename ):
975
955
# Pillow properly decodes this one, but we don't (order of parts of the
976
956
# image is wrong). This is due to a bug that was recently fixed in
@@ -980,8 +960,6 @@ def test_decode_avif_heic_against_pil(decode_fun, scripted, mode, pil_mode, file
980
960
import pillow_avif # noqa
981
961
982
962
encoded_bytes = read_file (filename )
983
- if scripted :
984
- decode_fun = torch .jit .script (decode_fun )
985
963
try :
986
964
img = decode_fun (encoded_bytes , mode = mode )
987
965
except RuntimeError as e :
@@ -994,6 +972,7 @@ def test_decode_avif_heic_against_pil(decode_fun, scripted, mode, pil_mode, file
994
972
"no 'ispe' property" ,
995
973
"'iref' has double references" ,
996
974
"Invalid image grid" ,
975
+ "decode_heif failed: Invalid input: No 'meta' box" ,
997
976
)
998
977
):
999
978
pytest .skip (reason = "Expected failure, that's OK" )
@@ -1010,7 +989,7 @@ def test_decode_avif_heic_against_pil(decode_fun, scripted, mode, pil_mode, file
1010
989
try :
1011
990
from_pil = F .pil_to_tensor (Image .open (filename ).convert (pil_mode ))
1012
991
except RuntimeError as e :
1013
- if "Invalid image grid" in str ( e ):
992
+ if any ( s in str ( e ) for s in ( "Invalid image grid" , "Failed to decode image: Not implemented" ) ):
1014
993
pytest .skip (reason = "PIL failure" )
1015
994
else :
1016
995
raise e
@@ -1021,7 +1000,7 @@ def test_decode_avif_heic_against_pil(decode_fun, scripted, mode, pil_mode, file
1021
1000
g = make_grid ([img , from_pil ])
1022
1001
F .to_pil_image (g ).save ((f"/home/nicolashug/out_images/{ filename .name } .{ pil_mode } .png" ))
1023
1002
1024
- is_decode_heic = getattr (decode_fun , "__name__" , getattr (decode_fun , "name" , None )) == "_decode_heic "
1003
+ is_decode_heic = getattr (decode_fun , "__name__" , getattr (decode_fun , "name" , None )) == "decode_heic "
1025
1004
if mode == ImageReadMode .RGB and not is_decode_heic :
1026
1005
# We don't compare torchvision's AVIF against PIL for RGB because
1027
1006
# results look pretty different on RGBA images (other images are fine).
@@ -1035,13 +1014,10 @@ def test_decode_avif_heic_against_pil(decode_fun, scripted, mode, pil_mode, file
1035
1014
torch .testing .assert_close (img , from_pil , rtol = 0 , atol = 3 )
1036
1015
1037
1016
1038
- @pytest .mark .skipif (not DECODE_HEIC_ENABLED , reason = "HEIC support not enabled yet." )
1039
- @pytest .mark .parametrize ("decode_fun" , (_decode_heic , decode_image ))
1040
- @pytest .mark .parametrize ("scripted" , (False , True ))
1041
- def test_decode_heic (decode_fun , scripted ):
1017
+ @pytest .mark .skipif (not IS_LINUX , reason = HEIC_AVIF_MESSAGE )
1018
+ @pytest .mark .parametrize ("decode_fun" , (decode_heic ,))
1019
+ def test_decode_heic (decode_fun ):
1042
1020
encoded_bytes = read_file (next (get_images (FAKEDATA_DIR , ".heic" )))
1043
- if scripted :
1044
- decode_fun = torch .jit .script (decode_fun )
1045
1021
img = decode_fun (encoded_bytes )
1046
1022
assert img .shape == (3 , 100 , 100 )
1047
1023
assert img [None ].is_contiguous (memory_format = torch .channels_last )
@@ -1080,13 +1056,5 @@ def test_mode_str():
1080
1056
assert decode_image (path , mode = "RGBA" ).shape [0 ] == 4
1081
1057
1082
1058
1083
- def test_avif_heic_fbcode ():
1084
- cm = nullcontext () if IN_FBCODE else pytest .raises (ImportError , match = "cannot import" )
1085
- with cm :
1086
- from torchvision .io import decode_heic # noqa
1087
- with cm :
1088
- from torchvision .io import decode_avif # noqa
1089
-
1090
-
1091
1059
if __name__ == "__main__" :
1092
1060
pytest .main ([__file__ ])
0 commit comments