Start adding HEIF support

This commit is contained in:
Paul Friederichsen 2023-08-02 05:37:45 -05:00
parent 50e5482740
commit 2887be614c
3 changed files with 82 additions and 11 deletions

View File

@ -718,6 +718,12 @@ APPLICATION_KRITA = 55
IMAGE_SVG = 56
APPLICATION_XCF = 57
APPLICATION_GZIP = 58
IMAGE_HEIF = 59
IMAGE_HEIF_SEQUENCE = 60
IMAGE_HEIC = 61
IMAGE_HEIC_SEQUENCE = 62
IMAGE_AVIF = 63
IMAGE_AVIF_SEQUENCE = 64
APPLICATION_OCTET_STREAM = 100
APPLICATION_UNKNOWN = 101
@ -738,6 +744,12 @@ SEARCHABLE_MIMES = {
IMAGE_TIFF,
IMAGE_ICON,
IMAGE_SVG,
IMAGE_HEIF,
IMAGE_HEIF_SEQUENCE,
IMAGE_HEIC,
IMAGE_HEIC_SEQUENCE,
IMAGE_AVIF,
IMAGE_AVIF_SEQUENCE,
APPLICATION_FLASH,
VIDEO_AVI,
VIDEO_FLV,
@ -787,12 +799,18 @@ IMAGES = {
IMAGE_BMP,
IMAGE_WEBP,
IMAGE_TIFF,
IMAGE_ICON
IMAGE_ICON,
IMAGE_HEIF,
IMAGE_HEIC,
IMAGE_AVIF,
}
ANIMATIONS = {
IMAGE_GIF,
IMAGE_APNG
IMAGE_APNG,
IMAGE_HEIF_SEQUENCE,
IMAGE_HEIC_SEQUENCE,
IMAGE_AVIF_SEQUENCE,
}
AUDIO = {
@ -853,7 +871,13 @@ for ( general_mime_type, mimes_in_type ) in general_mimetypes_to_mime_groups.ite
mimes_to_general_mimetypes[ mime ] = general_mime_type
PIL_HEIF_MIMES = {
IMAGE_HEIF,
IMAGE_HEIF_SEQUENCE,
IMAGE_HEIC,
IMAGE_HEIC_SEQUENCE,
IMAGE_AVIF,
}
MIMES_THAT_DEFINITELY_HAVE_AUDIO = tuple( [ APPLICATION_FLASH ] + list( AUDIO ) )
MIMES_THAT_MAY_HAVE_AUDIO = tuple( list( MIMES_THAT_DEFINITELY_HAVE_AUDIO ) + list( VIDEO ) )
@ -862,11 +886,11 @@ ARCHIVES = { APPLICATION_ZIP, APPLICATION_HYDRUS_ENCRYPTED_ZIP, APPLICATION_RAR,
MIMES_WITH_THUMBNAILS = set( IMAGES ).union( ANIMATIONS ).union( VIDEO ).union( { IMAGE_SVG, APPLICATION_FLASH, APPLICATION_CLIP, APPLICATION_PSD, APPLICATION_KRITA } )
FILES_THAT_CAN_HAVE_ICC_PROFILE = { IMAGE_JPEG, IMAGE_PNG, IMAGE_GIF, IMAGE_TIFF }
FILES_THAT_CAN_HAVE_ICC_PROFILE = { IMAGE_JPEG, IMAGE_PNG, IMAGE_GIF, IMAGE_TIFF }.union( PIL_HEIF_MIMES )
FILES_THAT_CAN_HAVE_EXIF = { IMAGE_JPEG, IMAGE_TIFF, IMAGE_PNG, IMAGE_WEBP }
FILES_THAT_CAN_HAVE_EXIF = { IMAGE_JPEG, IMAGE_TIFF, IMAGE_PNG, IMAGE_WEBP }.union( PIL_HEIF_MIMES )
# images and animations that PIL can handle
FILES_THAT_CAN_HAVE_HUMAN_READABLE_EMBEDDED_METADATA = { IMAGE_JPEG, IMAGE_PNG, IMAGE_BMP, IMAGE_WEBP, IMAGE_TIFF, IMAGE_ICON, IMAGE_GIF, IMAGE_APNG }
FILES_THAT_CAN_HAVE_HUMAN_READABLE_EMBEDDED_METADATA = { IMAGE_JPEG, IMAGE_PNG, IMAGE_BMP, IMAGE_WEBP, IMAGE_TIFF, IMAGE_ICON, IMAGE_GIF, IMAGE_APNG }.union( PIL_HEIF_MIMES )
FILES_THAT_CAN_HAVE_PIXEL_HASH = set( IMAGES ).union( { IMAGE_GIF } )
FILES_THAT_HAVE_PERCEPTUAL_HASH = set( IMAGES )
@ -887,6 +911,12 @@ mime_enum_lookup = {
'image/tiff' : IMAGE_TIFF,
'image/x-icon' : IMAGE_ICON,
'image/svg+xml': IMAGE_SVG,
'image/heif' : IMAGE_HEIF,
'image/heif-sequence' : IMAGE_HEIF_SEQUENCE,
'image/heic' : IMAGE_HEIC,
'image/heic-sequence' : IMAGE_HEIC_SEQUENCE,
'image/avif' : IMAGE_AVIF,
'image/avif-sequence' : IMAGE_AVIF_SEQUENCE,
'image/vnd.microsoft.icon' : IMAGE_ICON,
'image' : IMAGES,
'application/x-shockwave-flash' : APPLICATION_FLASH,
@ -950,6 +980,12 @@ mime_string_lookup = {
IMAGE_TIFF : 'tiff',
IMAGE_ICON : 'icon',
IMAGE_SVG : 'svg',
IMAGE_HEIF: 'heif',
IMAGE_HEIF_SEQUENCE: 'heif sequence',
IMAGE_HEIC: 'heic',
IMAGE_HEIC_SEQUENCE: 'heic sequence',
IMAGE_AVIF: 'avif',
IMAGE_AVIF_SEQUENCE: 'avif sequence',
APPLICATION_FLASH : 'flash',
APPLICATION_OCTET_STREAM : 'application/octet-stream',
APPLICATION_YAML : 'yaml',
@ -1014,6 +1050,12 @@ mime_mimetype_string_lookup = {
IMAGE_TIFF : 'image/tiff',
IMAGE_ICON : 'image/x-icon',
IMAGE_SVG : 'image/svg+xml',
IMAGE_HEIF: 'image/heif',
IMAGE_HEIF_SEQUENCE: 'image/heif-sequence',
IMAGE_HEIC: 'image/heic',
IMAGE_HEIC_SEQUENCE: 'image/heic-sequence',
IMAGE_AVIF: 'image/avif',
IMAGE_AVIF_SEQUENCE: 'image/avif-sequence',
APPLICATION_FLASH : 'application/x-shockwave-flash',
APPLICATION_OCTET_STREAM : 'application/octet-stream',
APPLICATION_YAML : 'application/x-yaml',
@ -1079,6 +1121,12 @@ mime_ext_lookup = {
IMAGE_TIFF : '.tiff',
IMAGE_ICON : '.ico',
IMAGE_SVG : '.svg',
IMAGE_HEIF: 'heif',
IMAGE_HEIF_SEQUENCE: 'heifs',
IMAGE_HEIC: 'heic',
IMAGE_HEIC_SEQUENCE: 'heics',
IMAGE_AVIF: 'avif',
IMAGE_AVIF_SEQUENCE: 'avifs',
APPLICATION_FLASH : '.swf',
APPLICATION_OCTET_STREAM : '.bin',
APPLICATION_YAML : '.yaml',

View File

@ -79,6 +79,21 @@ headers_and_mime.extend( [
( ( ( 0, b'\x52\x61\x72\x21\x1A\x07\x01\x00' ), ), HC.APPLICATION_RAR ),
( ( ( 0, b'\x1f\x8b' ), ), HC.APPLICATION_GZIP ),
( ( ( 0, b'hydrus encrypted zip' ), ), HC.APPLICATION_HYDRUS_ENCRYPTED_ZIP ),
( ( ( 4, b'ftypavif' ), ), HC.IMAGE_AVIF ),
( ( ( 4, b'ftypavis' ), ), HC.IMAGE_AVIF_SEQUENCE ),
( ( ( 4, b'ftypmif1' ), ( 16, b'avif' ), ), HC.IMAGE_AVIF ),
( ( ( 4, b'ftypmif1' ), ( 20, b'avif' ), ), HC.IMAGE_AVIF ),
( ( ( 4, b'ftypmif1' ), ( 24, b'avif' ), ), HC.IMAGE_AVIF ),
( ( ( 4, b'ftypheic' ), ), HC.IMAGE_HEIC ),
( ( ( 4, b'ftypheix' ), ), HC.IMAGE_HEIC ),
( ( ( 4, b'ftypheim' ), ), HC.IMAGE_HEIC ),
( ( ( 4, b'ftypheis' ), ), HC.IMAGE_HEIC ),
( ( ( 4, b'ftyphevc' ), ), HC.IMAGE_HEIC_SEQUENCE ),
( ( ( 4, b'ftyphevx' ), ), HC.IMAGE_HEIC_SEQUENCE ),
( ( ( 4, b'ftyphevm' ), ), HC.IMAGE_HEIC_SEQUENCE ),
( ( ( 4, b'ftyphevs' ), ), HC.IMAGE_HEIC_SEQUENCE ),
( ( ( 4, b'ftypmif1' ), ), HC.IMAGE_HEIF ),
( ( ( 4, b'ftypsf1' ), ), HC.IMAGE_HEIF_SEQUENCE ),
( ( ( 4, b'ftypmp4' ), ), HC.UNDETERMINED_MP4 ),
( ( ( 4, b'ftypisom' ), ), HC.UNDETERMINED_MP4 ),
( ( ( 4, b'ftypM4V' ), ), HC.UNDETERMINED_MP4 ),
@ -102,7 +117,7 @@ def GenerateThumbnailBytes( path, target_resolution, mime, duration, num_frames,
target_resolution = ( 128, 128 )
if mime in ( HC.IMAGE_JPEG, HC.IMAGE_PNG, HC.IMAGE_GIF, HC.IMAGE_WEBP, HC.IMAGE_TIFF, HC.IMAGE_ICON ): # not apng atm
if mime in { HC.IMAGE_JPEG, HC.IMAGE_PNG, HC.IMAGE_GIF, HC.IMAGE_WEBP, HC.IMAGE_TIFF, HC.IMAGE_ICON }.union( HC.PIL_HEIF_MIMES ): # not apng atm
try:
@ -353,7 +368,7 @@ def GetFileInfo( path, mime = None, ok_to_look_for_hydrus_updates = False ):
has_audio = False
if mime in ( HC.IMAGE_JPEG, HC.IMAGE_PNG, HC.IMAGE_GIF, HC.IMAGE_WEBP, HC.IMAGE_TIFF, HC.IMAGE_ICON ):
if mime in { HC.IMAGE_JPEG, HC.IMAGE_PNG, HC.IMAGE_GIF, HC.IMAGE_WEBP, HC.IMAGE_TIFF, HC.IMAGE_ICON }.union( HC.PIL_HEIF_MIMES ):
( ( width, height ), duration, num_frames ) = HydrusImageHandling.GetImageProperties( path, mime )

View File

@ -26,6 +26,12 @@ from PIL import ImageFile as PILImageFile
from PIL import Image as PILImage
from PIL import ImageCms as PILImageCms
from pillow_heif import register_heif_opener
from pillow_heif import register_avif_opener
register_heif_opener(thumbnails=False)
register_avif_opener(thumbnails=False)
from hydrus.core import HydrusConstants as HC
from hydrus.core import HydrusData
from hydrus.core import HydrusExceptions
@ -79,7 +85,7 @@ warnings.simplefilter( 'ignore', PILImage.DecompressionBombError )
OLD_PIL_MAX_IMAGE_PIXELS = PILImage.MAX_IMAGE_PIXELS
PILImage.MAX_IMAGE_PIXELS = None # this turns off decomp check entirely, wew
PIL_ONLY_MIMETYPES = { HC.IMAGE_GIF, HC.IMAGE_ICON }
PIL_ONLY_MIMETYPES = { HC.IMAGE_GIF, HC.IMAGE_ICON }.union( HC.PIL_HEIF_MIMES )
try:
@ -817,8 +823,8 @@ def GetResolutionNumPy( numpy_image ):
def GetResolutionAndNumFramesPIL( path, mime ):
pil_image = GeneratePILImage( path, dequantize = False )
pil_image = GeneratePILImage( path, dequantize = False )
( x, y ) = pil_image.size
if mime == HC.IMAGE_GIF: # some jpegs came up with 2 frames and 'duration' because of some embedded thumbnail in the metadata
@ -1222,6 +1228,8 @@ def RawOpenPILImage( path ) -> PILImage.Image:
pil_image = PILImage.open( path )
except Exception as e:
print(e)
raise HydrusExceptions.DamagedOrUnusualFileException( 'Could not load the image--it was likely malformed!' )