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 IMAGE_SVG = 56
APPLICATION_XCF = 57 APPLICATION_XCF = 57
APPLICATION_GZIP = 58 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_OCTET_STREAM = 100
APPLICATION_UNKNOWN = 101 APPLICATION_UNKNOWN = 101
@ -738,6 +744,12 @@ SEARCHABLE_MIMES = {
IMAGE_TIFF, IMAGE_TIFF,
IMAGE_ICON, IMAGE_ICON,
IMAGE_SVG, IMAGE_SVG,
IMAGE_HEIF,
IMAGE_HEIF_SEQUENCE,
IMAGE_HEIC,
IMAGE_HEIC_SEQUENCE,
IMAGE_AVIF,
IMAGE_AVIF_SEQUENCE,
APPLICATION_FLASH, APPLICATION_FLASH,
VIDEO_AVI, VIDEO_AVI,
VIDEO_FLV, VIDEO_FLV,
@ -787,12 +799,18 @@ IMAGES = {
IMAGE_BMP, IMAGE_BMP,
IMAGE_WEBP, IMAGE_WEBP,
IMAGE_TIFF, IMAGE_TIFF,
IMAGE_ICON IMAGE_ICON,
IMAGE_HEIF,
IMAGE_HEIC,
IMAGE_AVIF,
} }
ANIMATIONS = { ANIMATIONS = {
IMAGE_GIF, IMAGE_GIF,
IMAGE_APNG IMAGE_APNG,
IMAGE_HEIF_SEQUENCE,
IMAGE_HEIC_SEQUENCE,
IMAGE_AVIF_SEQUENCE,
} }
AUDIO = { 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 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_DEFINITELY_HAVE_AUDIO = tuple( [ APPLICATION_FLASH ] + list( AUDIO ) )
MIMES_THAT_MAY_HAVE_AUDIO = tuple( list( MIMES_THAT_DEFINITELY_HAVE_AUDIO ) + list( VIDEO ) ) 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 } ) 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 # 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_CAN_HAVE_PIXEL_HASH = set( IMAGES ).union( { IMAGE_GIF } )
FILES_THAT_HAVE_PERCEPTUAL_HASH = set( IMAGES ) FILES_THAT_HAVE_PERCEPTUAL_HASH = set( IMAGES )
@ -887,6 +911,12 @@ mime_enum_lookup = {
'image/tiff' : IMAGE_TIFF, 'image/tiff' : IMAGE_TIFF,
'image/x-icon' : IMAGE_ICON, 'image/x-icon' : IMAGE_ICON,
'image/svg+xml': IMAGE_SVG, '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/vnd.microsoft.icon' : IMAGE_ICON,
'image' : IMAGES, 'image' : IMAGES,
'application/x-shockwave-flash' : APPLICATION_FLASH, 'application/x-shockwave-flash' : APPLICATION_FLASH,
@ -950,6 +980,12 @@ mime_string_lookup = {
IMAGE_TIFF : 'tiff', IMAGE_TIFF : 'tiff',
IMAGE_ICON : 'icon', IMAGE_ICON : 'icon',
IMAGE_SVG : 'svg', 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_FLASH : 'flash',
APPLICATION_OCTET_STREAM : 'application/octet-stream', APPLICATION_OCTET_STREAM : 'application/octet-stream',
APPLICATION_YAML : 'yaml', APPLICATION_YAML : 'yaml',
@ -1014,6 +1050,12 @@ mime_mimetype_string_lookup = {
IMAGE_TIFF : 'image/tiff', IMAGE_TIFF : 'image/tiff',
IMAGE_ICON : 'image/x-icon', IMAGE_ICON : 'image/x-icon',
IMAGE_SVG : 'image/svg+xml', 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_FLASH : 'application/x-shockwave-flash',
APPLICATION_OCTET_STREAM : 'application/octet-stream', APPLICATION_OCTET_STREAM : 'application/octet-stream',
APPLICATION_YAML : 'application/x-yaml', APPLICATION_YAML : 'application/x-yaml',
@ -1079,6 +1121,12 @@ mime_ext_lookup = {
IMAGE_TIFF : '.tiff', IMAGE_TIFF : '.tiff',
IMAGE_ICON : '.ico', IMAGE_ICON : '.ico',
IMAGE_SVG : '.svg', 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_FLASH : '.swf',
APPLICATION_OCTET_STREAM : '.bin', APPLICATION_OCTET_STREAM : '.bin',
APPLICATION_YAML : '.yaml', 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'\x52\x61\x72\x21\x1A\x07\x01\x00' ), ), HC.APPLICATION_RAR ),
( ( ( 0, b'\x1f\x8b' ), ), HC.APPLICATION_GZIP ), ( ( ( 0, b'\x1f\x8b' ), ), HC.APPLICATION_GZIP ),
( ( ( 0, b'hydrus encrypted zip' ), ), HC.APPLICATION_HYDRUS_ENCRYPTED_ZIP ), ( ( ( 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'ftypmp4' ), ), HC.UNDETERMINED_MP4 ),
( ( ( 4, b'ftypisom' ), ), HC.UNDETERMINED_MP4 ), ( ( ( 4, b'ftypisom' ), ), HC.UNDETERMINED_MP4 ),
( ( ( 4, b'ftypM4V' ), ), 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 ) 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: try:
@ -353,7 +368,7 @@ def GetFileInfo( path, mime = None, ok_to_look_for_hydrus_updates = False ):
has_audio = 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 ) ( ( 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 Image as PILImage
from PIL import ImageCms as PILImageCms 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 HydrusConstants as HC
from hydrus.core import HydrusData from hydrus.core import HydrusData
from hydrus.core import HydrusExceptions from hydrus.core import HydrusExceptions
@ -79,7 +85,7 @@ warnings.simplefilter( 'ignore', PILImage.DecompressionBombError )
OLD_PIL_MAX_IMAGE_PIXELS = PILImage.MAX_IMAGE_PIXELS OLD_PIL_MAX_IMAGE_PIXELS = PILImage.MAX_IMAGE_PIXELS
PILImage.MAX_IMAGE_PIXELS = None # this turns off decomp check entirely, wew 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: try:
@ -1223,6 +1229,8 @@ def RawOpenPILImage( path ) -> PILImage.Image:
except Exception as e: except Exception as e:
print(e)
raise HydrusExceptions.DamagedOrUnusualFileException( 'Could not load the image--it was likely malformed!' ) raise HydrusExceptions.DamagedOrUnusualFileException( 'Could not load the image--it was likely malformed!' )