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 }  ))
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