44import os
55import re
66import sys
7- from contextlib import nullcontext
87from pathlib import Path
98
109import numpy as np
1413import torchvision .transforms .v2 .functional as F
1514from common_utils import assert_equal , cpu_and_cuda , IN_OSS_CI , needs_cuda
1615from PIL import __version__ as PILLOW_VERSION , Image , ImageOps , ImageSequence
17- from torchvision ._internally_replaced_utils import IN_FBCODE
1816from torchvision .io .image import (
19- _decode_avif ,
20- _decode_heic ,
17+ decode_avif ,
2118 decode_gif ,
19+ decode_heic ,
2220 decode_image ,
2321 decode_jpeg ,
2422 decode_png ,
4341TOOSMALL_PNG = os .path .join (IMAGE_ROOT , "toosmall_png" )
4442IS_WINDOWS = sys .platform in ("win32" , "cygwin" )
4543IS_MACOS = sys .platform == "darwin"
44+ IS_LINUX = sys .platform == "linux"
4645PILLOW_VERSION = tuple (int (x ) for x in PILLOW_VERSION .split ("." ))
4746WEBP_TEST_IMAGES_DIR = os .environ .get ("WEBP_TEST_IMAGES_DIR" , "" )
4847# 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."
6249
6350
6451def _get_safe_image_name (name ):
@@ -866,19 +853,23 @@ def test_decode_gif(tmpdir, name, scripted):
866853 torch .testing .assert_close (tv_frame , pil_frame , atol = 0 , rtol = 0 )
867854
868855
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+ )
882873def test_decode_bad_encoded_data (decode_fun , match ):
883874 encoded_data = torch .randint (0 , 256 , (100 ,), dtype = torch .uint8 )
884875 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)
934925 img += 123 # make sure image buffer wasn't freed by underlying decoding lib
935926
936927
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 ):
941931 encoded_bytes = read_file (next (get_images (FAKEDATA_DIR , ".avif" )))
942- if scripted :
943- decode_fun = torch .jit .script (decode_fun )
944932 img = decode_fun (encoded_bytes )
945933 assert img .shape == (3 , 100 , 100 )
946934 assert img [None ].is_contiguous (memory_format = torch .channels_last )
@@ -949,16 +937,8 @@ def test_decode_avif(decode_fun, scripted):
949937
950938# Note: decode_image fails because some of these files have a (valid) signature
951939# 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 ))
962942@pytest .mark .parametrize (
963943 "mode, pil_mode" ,
964944 (
@@ -970,7 +950,7 @@ def test_decode_avif(decode_fun, scripted):
970950@pytest .mark .parametrize (
971951 "filename" , Path ("/home/nicolashug/dev/libavif/tests/data/" ).glob ("*.avif" ), ids = lambda p : p .name
972952)
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 ):
974954 if "reversed_dimg_order" in str (filename ):
975955 # Pillow properly decodes this one, but we don't (order of parts of the
976956 # 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
980960 import pillow_avif # noqa
981961
982962 encoded_bytes = read_file (filename )
983- if scripted :
984- decode_fun = torch .jit .script (decode_fun )
985963 try :
986964 img = decode_fun (encoded_bytes , mode = mode )
987965 except RuntimeError as e :
@@ -994,6 +972,7 @@ def test_decode_avif_heic_against_pil(decode_fun, scripted, mode, pil_mode, file
994972 "no 'ispe' property" ,
995973 "'iref' has double references" ,
996974 "Invalid image grid" ,
975+ "decode_heif failed: Invalid input: No 'meta' box" ,
997976 )
998977 ):
999978 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
1010989 try :
1011990 from_pil = F .pil_to_tensor (Image .open (filename ).convert (pil_mode ))
1012991 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" ) ):
1014993 pytest .skip (reason = "PIL failure" )
1015994 else :
1016995 raise e
@@ -1021,7 +1000,7 @@ def test_decode_avif_heic_against_pil(decode_fun, scripted, mode, pil_mode, file
10211000 g = make_grid ([img , from_pil ])
10221001 F .to_pil_image (g ).save ((f"/home/nicolashug/out_images/{ filename .name } .{ pil_mode } .png" ))
10231002
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 "
10251004 if mode == ImageReadMode .RGB and not is_decode_heic :
10261005 # We don't compare torchvision's AVIF against PIL for RGB because
10271006 # 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
10351014 torch .testing .assert_close (img , from_pil , rtol = 0 , atol = 3 )
10361015
10371016
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 ):
10421020 encoded_bytes = read_file (next (get_images (FAKEDATA_DIR , ".heic" )))
1043- if scripted :
1044- decode_fun = torch .jit .script (decode_fun )
10451021 img = decode_fun (encoded_bytes )
10461022 assert img .shape == (3 , 100 , 100 )
10471023 assert img [None ].is_contiguous (memory_format = torch .channels_last )
@@ -1080,13 +1056,5 @@ def test_mode_str():
10801056 assert decode_image (path , mode = "RGBA" ).shape [0 ] == 4
10811057
10821058
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-
10911059if __name__ == "__main__" :
10921060 pytest .main ([__file__ ])
0 commit comments