Add djvu file support (#1453)

* Reorganize header to mime stuff

* Fix changes to headers and mime stuff

* Add djvu file support

* Change function order in HydrusFileHandling

* Fix some spacing
This commit is contained in:
Paul Friederichsen 2023-10-07 14:14:35 -05:00 committed by GitHub
parent 343e12a94d
commit af135ece79
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 64 additions and 79 deletions

View File

@ -790,7 +790,7 @@ class ThumbnailCache( object ):
self._special_thumbs = {}
names = [ 'hydrus', 'pdf', 'psd', 'clip', 'sai', 'krita', 'xcf', 'svg', 'audio', 'video', 'zip', 'epub' ]
names = [ 'hydrus', 'pdf', 'psd', 'clip', 'sai', 'krita', 'xcf', 'svg', 'audio', 'video', 'zip', 'epub', 'djvu' ]
bounding_dimensions = self._controller.options[ 'thumbnail_dimensions' ]
thumbnail_scale_type = self._controller.new_options.GetInteger( 'thumbnail_scale_type' )
@ -906,6 +906,7 @@ class ThumbnailCache( object ):
elif mime in HC.VIDEO: return self._special_thumbs[ 'video' ]
elif mime == HC.APPLICATION_PDF: return self._special_thumbs[ 'pdf' ]
elif mime == HC.APPLICATION_EPUB: return self._special_thumbs[ 'epub' ]
elif mime == HC.APPLICATION_DJVU: return self._special_thumbs[ 'djvu' ]
elif mime == HC.APPLICATION_PSD: return self._special_thumbs[ 'psd' ]
elif mime == HC.APPLICATION_SAI2: return self._special_thumbs[ 'sai' ]
elif mime == HC.APPLICATION_KRITA: return self._special_thumbs[ 'krita' ]

View File

@ -734,6 +734,7 @@ IMAGE_GIF = 68
APPLICATION_PROCREATE = 69
IMAGE_QOI = 70
APPLICATION_EPUB = 71
APPLICATION_DJVU = 72
APPLICATION_OCTET_STREAM = 100
APPLICATION_UNKNOWN = 101
@ -783,6 +784,7 @@ SEARCHABLE_MIMES = {
APPLICATION_PROCREATE,
APPLICATION_PDF,
APPLICATION_EPUB,
APPLICATION_DJVU,
APPLICATION_ZIP,
APPLICATION_RAR,
APPLICATION_7Z,
@ -867,7 +869,8 @@ VIDEO = [
APPLICATIONS = [
APPLICATION_FLASH,
APPLICATION_PDF,
APPLICATION_EPUB
APPLICATION_EPUB,
APPLICATION_DJVU
]
IMAGE_PROJECT_FILES = [
@ -978,6 +981,9 @@ mime_enum_lookup = {
'PDF document' : APPLICATION_PDF,
'application/pdf' : APPLICATION_PDF,
'application/epub+zip' : APPLICATION_EPUB,
'image/vnd.djvu' : APPLICATION_DJVU,
'image/vnd.djvu+multipage' : APPLICATION_DJVU,
'image/x-djvu' : APPLICATION_DJVU,
'application/zip' : APPLICATION_ZIP,
'application/vnd.rar' : APPLICATION_RAR,
'application/x-7z-compressed' : APPLICATION_7Z,
@ -1042,6 +1048,7 @@ mime_string_lookup = {
APPLICATION_CBOR : 'cbor',
APPLICATION_PDF : 'pdf',
APPLICATION_EPUB : 'epub',
APPLICATION_DJVU : 'djvu',
APPLICATION_PSD : 'psd',
APPLICATION_CLIP : 'clip',
APPLICATION_SAI2 : 'sai2',
@ -1120,6 +1127,7 @@ mime_mimetype_string_lookup = {
APPLICATION_CBOR : 'application/cbor',
APPLICATION_PDF : 'application/pdf',
APPLICATION_EPUB : 'application/epub+zip',
APPLICATION_DJVU : 'image/vnd.djvu',
APPLICATION_PSD : 'image/vnd.adobe.photoshop',
APPLICATION_CLIP : 'application/clip', # made up
APPLICATION_SAI2: 'application/sai2', # made up
@ -1196,6 +1204,7 @@ mime_ext_lookup = {
APPLICATION_JSON : '.json',
APPLICATION_PDF : '.pdf',
APPLICATION_EPUB : '.epub',
APPLICATION_DJVU : '.djvu',
APPLICATION_PSD : '.psd',
APPLICATION_CLIP : '.clip',
APPLICATION_SAI2: '.sai2',

View File

@ -41,80 +41,6 @@ except Exception as e:
SPEEDCOPY_OK = False
# Mime
headers_and_mime_thumbnails = [
( ( ( 0, b'\xff\xd8' ), ), HC.IMAGE_JPEG ),
( ( ( 0, b'\x89PNG' ), ), HC.UNDETERMINED_PNG )
]
headers_and_mime = list( headers_and_mime_thumbnails )
headers_and_mime.extend( [
( ( ( 0, b'GIF87a' ), ), HC.UNDETERMINED_GIF ),
( ( ( 0, b'GIF89a' ), ), HC.UNDETERMINED_GIF ),
( ( ( 0, b'\x89PNG' ), ), HC.UNDETERMINED_PNG ),
( ( ( 8, b'WEBP' ), ), HC.IMAGE_WEBP ),
( ( ( 0, b'II*\x00' ), ), HC.IMAGE_TIFF ),
( ( ( 0, b'MM\x00*' ), ), HC.IMAGE_TIFF ),
( ( ( 0, b'BM' ), ), HC.IMAGE_BMP ),
( ( ( 0, b'\x00\x00\x01\x00' ), ), HC.IMAGE_ICON ),
( ( ( 0, b'\x00\x00\x02\x00' ), ), HC.IMAGE_ICON ),
( ( ( 0, b'qoif' ), ), HC.IMAGE_QOI ),
( ( ( 0, b'CWS' ), ), HC.APPLICATION_FLASH ),
( ( ( 0, b'FWS' ), ), HC.APPLICATION_FLASH ),
( ( ( 0, b'ZWS' ), ), HC.APPLICATION_FLASH ),
( ( ( 0, b'FLV' ), ), HC.VIDEO_FLV ),
( ( ( 0, b'%PDF' ), ), HC.APPLICATION_PDF ),
( ( ( 0, b'8BPS\x00\x01' ), ), HC.APPLICATION_PSD ),
( ( ( 0, b'8BPS\x00\x02' ), ), HC.APPLICATION_PSD ), # PSB, which is basically PSD v2 and does giganto resolution
( ( ( 0, b'CSFCHUNK' ), ), HC.APPLICATION_CLIP ),
( ( ( 0, b'SAI-CANVAS' ), ), HC.APPLICATION_SAI2 ),
( ( ( 0, b'gimp xcf ' ), ), HC.APPLICATION_XCF ),
( ( ( 38, b'application/x-krita' ), ), HC.APPLICATION_KRITA ), # important this comes before zip files because this is also a zip file
( ( ( 42, b'application/x-krita' ), ), HC.APPLICATION_KRITA ), # https://gitlab.freedesktop.org/xdg/shared-mime-info/-/blob/master/data/freedesktop.org.xml.in#L2829
( ( ( 58, b'application/x-krita' ), ), HC.APPLICATION_KRITA ),
( ( ( 63, b'application/x-krita' ), ), HC.APPLICATION_KRITA ),
( ( ( 38, b'application/epub+zip' ), ), HC.APPLICATION_EPUB ),
( ( ( 43, b'application/epub+zip' ), ), HC.APPLICATION_EPUB ),
( ( ( 0, b'PK\x03\x04' ), ), HC.APPLICATION_ZIP ),
( ( ( 0, b'PK\x05\x06' ), ), HC.APPLICATION_ZIP ),
( ( ( 0, b'PK\x07\x08' ), ), HC.APPLICATION_ZIP ),
( ( ( 0, b'7z\xBC\xAF\x27\x1C' ), ), HC.APPLICATION_7Z ),
( ( ( 0, b'\x52\x61\x72\x21\x1A\x07\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'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'ftypmsf1' ), ), HC.IMAGE_HEIF_SEQUENCE ),
( ( ( 4, b'ftypmp4' ), ), HC.UNDETERMINED_MP4 ),
( ( ( 4, b'ftypisom' ), ), HC.UNDETERMINED_MP4 ),
( ( ( 4, b'ftypM4V' ), ), HC.UNDETERMINED_MP4 ),
( ( ( 4, b'ftypMSNV' ), ), HC.UNDETERMINED_MP4 ),
( ( ( 4, b'ftypavc1' ), ), HC.UNDETERMINED_MP4 ),
( ( ( 4, b'ftypFACE' ), ), HC.UNDETERMINED_MP4 ),
( ( ( 4, b'ftypdash' ), ), HC.UNDETERMINED_MP4 ),
( ( ( 4, b'ftypqt' ), ), HC.VIDEO_MOV ),
( ( ( 0, b'fLaC' ), ), HC.AUDIO_FLAC ),
( ( ( 0, b'RIFF' ), ( 8, b'WAVE' ) ), HC.AUDIO_WAVE ),
( ( ( 0, b'wvpk' ), ), HC.AUDIO_WAVPACK ),
( ( ( 8, b'AVI ' ), ), HC.VIDEO_AVI ),
( ( ( 0, b'\x30\x26\xB2\x75\x8E\x66\xCF\x11\xA6\xD9\x00\xAA\x00\x62\xCE\x6C' ), ), HC.UNDETERMINED_WM ),
( ( ( 0, b'\x4D\x5A\x90\x00\x03', ), ), HC.APPLICATION_WINDOWS_EXE )
] )
def GenerateThumbnailBytes( path, target_resolution, mime, duration, num_frames, clip_rect = None, percentage_in = 35 ):
@ -578,6 +504,48 @@ def GetHashFromPath( path ):
return h.digest()
headers_and_mime = [
( ( ( [0], [b'\xff\xd8'] ), ), HC.IMAGE_JPEG ),
( ( ( [0], [b'\x89PNG'] ), ), HC.UNDETERMINED_PNG ),
( ( ( [0], [b'GIF87a', b'GIF89a'] ), ), HC.UNDETERMINED_GIF ),
( ( ( [8], [b'WEBP'] ), ), HC.IMAGE_WEBP ),
( ( ( [0], [b'II*\x00', b'MM\x00*'] ), ), HC.IMAGE_TIFF ),
( ( ( [0], [b'BM'] ), ), HC.IMAGE_BMP ),
( ( ( [0], [b'\x00\x00\x01\x00', b'\x00\x00\x02\x00'] ), ), HC.IMAGE_ICON ),
( ( ( [0], [b'qoif'] ), ), HC.IMAGE_QOI ),
( ( ( [0], [b'CWS', b'FWS', b'ZWS'] ), ), HC.APPLICATION_FLASH ),
( ( ( [0], [b'FLV'] ), ), HC.VIDEO_FLV ),
( ( ( [0], [b'%PDF'] ), ), HC.APPLICATION_PDF ),
( ( ( [0], [b'8BPS\x00\x01', b'8BPS\x00\x02'] ), ), HC.APPLICATION_PSD ),
( ( ( [0], [b'CSFCHUNK'] ), ), HC.APPLICATION_CLIP ),
( ( ( [0], [b'SAI-CANVAS'] ), ), HC.APPLICATION_SAI2 ),
( ( ( [0], [b'gimp xcf '] ), ), HC.APPLICATION_XCF ),
( ( ( [38, 42, 58, 63],[ b'application/x-krita'] ), ), HC.APPLICATION_KRITA ), # important this comes before zip files because this is also a zip file
( ( ( [38, 43],[ b'application/epub+zip'] ), ), HC.APPLICATION_EPUB ),
( ( ( [4], [b'FORM'] ), ( [12], [b'DJVU', b'DJVM', b'PM44', b'BM44', b'SDJV'] ), ), HC.APPLICATION_DJVU ),
( ( ( [0], [b'PK\x03\x04', b'PK\x05\x06', b'PK\x07\x08'] ), ), HC.APPLICATION_ZIP ),
( ( ( [0], [b'7z\xBC\xAF\x27\x1C'] ), ), HC.APPLICATION_7Z ),
( ( ( [0], [b'\x52\x61\x72\x21\x1A\x07\x00', 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, 20, 24], [b'avif'] ), ), HC.IMAGE_AVIF ),
( ( ( [4], [b'ftypheic', b'ftypheix', b'ftypheim', b'ftypheis'] ), ), HC.IMAGE_HEIC ),
( ( ( [4], [b'ftyphevc', b'ftyphevx', b'ftyphevm', b'ftyphevs'] ), ), HC.IMAGE_HEIC_SEQUENCE ),
( ( ( [4], [b'ftypmif1'] ), ), HC.IMAGE_HEIF ),
( ( ( [4], [b'ftypmsf1'] ), ), HC.IMAGE_HEIF_SEQUENCE ),
( ( ( [4], [b'ftypmp4', b'ftypisom', b'ftypM4V', b'ftypMSNV', b'ftypavc1', b'ftypavc1', b'ftypFACE', b'ftypdash'] ), ), HC.UNDETERMINED_MP4 ),
( ( ( [4], [b'ftypqt'] ), ), HC.VIDEO_MOV ),
( ( ( [0], [b'fLaC'] ), ), HC.AUDIO_FLAC ),
( ( ( [0], [b'RIFF'] ), ( 8, b'WAVE' ) ), HC.AUDIO_WAVE ),
( ( ( [0], [b'wvpk'] ), ), HC.AUDIO_WAVPACK ),
( ( ( [8], [b'AVI '] ), ), HC.VIDEO_AVI ),
( ( ( [0], [b'\x30\x26\xB2\x75\x8E\x66\xCF\x11\xA6\xD9\x00\xAA\x00\x62\xCE\x6C'] ), ), HC.UNDETERMINED_WM ),
( ( ( [0], [b'\x4D\x5A\x90\x00\x03'], ), ), HC.APPLICATION_WINDOWS_EXE )
]
def GetMime( path, ok_to_look_for_hydrus_updates = False ):
size = os.path.getsize( path )
@ -620,7 +588,7 @@ def GetMime( path, ok_to_look_for_hydrus_updates = False ):
for ( offsets_and_headers, mime ) in headers_and_mime:
it_passes = False not in ( first_bytes_of_file[ offset: ].startswith( header ) for ( offset, header ) in offsets_and_headers )
it_passes = False not in ( True in ( True in (first_bytes_of_file[ offset: ].startswith( header ) for offset in offsets) for header in headers) for ( offsets, headers ) in offsets_and_headers )
if it_passes:
@ -726,7 +694,14 @@ def GetMime( path, ok_to_look_for_hydrus_updates = False ):
return HC.APPLICATION_UNKNOWN
headers_and_mime_thumbnails = [
( ( ( 0, b'\xff\xd8' ), ), HC.IMAGE_JPEG ),
( ( ( 0, b'\x89PNG' ), ), HC.UNDETERMINED_PNG )
]
def GetThumbnailMime( path ):
with open( path, 'rb' ) as f:
@ -745,4 +720,3 @@ def GetThumbnailMime( path ):
return HC.APPLICATION_OCTET_STREAM

View File

@ -23,6 +23,7 @@ mimes_to_default_thumbnail_paths = collections.defaultdict( lambda: os.path.join
mimes_to_default_thumbnail_paths[ HC.APPLICATION_PDF ] = os.path.join( HC.STATIC_DIR, 'pdf.png' )
mimes_to_default_thumbnail_paths[ HC.APPLICATION_EPUB ] = os.path.join( HC.STATIC_DIR, 'epub.png' )
mimes_to_default_thumbnail_paths[ HC.APPLICATION_DJVU ] = os.path.join( HC.STATIC_DIR, 'djvu.png' )
mimes_to_default_thumbnail_paths[ HC.APPLICATION_PSD ] = os.path.join( HC.STATIC_DIR, 'psd.png' )
mimes_to_default_thumbnail_paths[ HC.APPLICATION_CLIP ] = os.path.join( HC.STATIC_DIR, 'clip.png' )
mimes_to_default_thumbnail_paths[ HC.APPLICATION_SAI2 ] = os.path.join( HC.STATIC_DIR, 'sai.png' )

BIN
static/djvu.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB