commit
64f946c58f
|
@ -744,7 +744,7 @@ class ThumbnailCache( object ):
|
|||
|
||||
self._special_thumbs = {}
|
||||
|
||||
names = [ 'hydrus', 'pdf', 'psd', 'clip', 'sai', 'krita', 'audio', 'video', 'zip' ]
|
||||
names = [ 'hydrus', 'pdf', 'psd', 'clip', 'sai', 'krita', 'svg', 'audio', 'video', 'zip' ]
|
||||
|
||||
bounding_dimensions = self._controller.options[ 'thumbnail_dimensions' ]
|
||||
thumbnail_scale_type = self._controller.new_options.GetInteger( 'thumbnail_scale_type' )
|
||||
|
@ -862,6 +862,7 @@ class ThumbnailCache( object ):
|
|||
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' ]
|
||||
elif mime == HC.IMAGE_SVG: return self._special_thumbs[ 'svg' ]
|
||||
elif mime in HC.ARCHIVES: return self._special_thumbs[ 'zip' ]
|
||||
else: return self._special_thumbs[ 'hydrus' ]
|
||||
|
||||
|
|
|
@ -715,12 +715,13 @@ APPLICATION_WINDOWS_EXE = 52
|
|||
AUDIO_WAVPACK = 53
|
||||
APPLICATION_SAI2 = 54
|
||||
APPLICATION_KRITA = 55
|
||||
IMAGE_SVG = 56
|
||||
APPLICATION_OCTET_STREAM = 100
|
||||
APPLICATION_UNKNOWN = 101
|
||||
|
||||
GENERAL_FILETYPES = { GENERAL_APPLICATION, GENERAL_AUDIO, GENERAL_IMAGE, GENERAL_VIDEO, GENERAL_ANIMATION }
|
||||
|
||||
SEARCHABLE_MIMES = { IMAGE_JPEG, IMAGE_PNG, IMAGE_APNG, IMAGE_GIF, IMAGE_WEBP, IMAGE_TIFF, IMAGE_ICON, APPLICATION_FLASH, VIDEO_AVI, VIDEO_FLV, VIDEO_MOV, VIDEO_MP4, VIDEO_MKV, VIDEO_REALMEDIA, VIDEO_WEBM, VIDEO_OGV, VIDEO_MPEG, APPLICATION_CLIP, APPLICATION_PSD, APPLICATION_SAI2, APPLICATION_KRITA, APPLICATION_PDF, APPLICATION_ZIP, APPLICATION_RAR, APPLICATION_7Z, AUDIO_M4A, AUDIO_MP3, AUDIO_REALMEDIA, AUDIO_OGG, AUDIO_FLAC, AUDIO_WAVE, AUDIO_TRUEAUDIO, AUDIO_WMA, VIDEO_WMV, AUDIO_MKV, AUDIO_MP4, AUDIO_WAVPACK }
|
||||
SEARCHABLE_MIMES = { IMAGE_JPEG, IMAGE_PNG, IMAGE_APNG, IMAGE_GIF, IMAGE_WEBP, IMAGE_TIFF, IMAGE_ICON, IMAGE_SVG, APPLICATION_FLASH, VIDEO_AVI, VIDEO_FLV, VIDEO_MOV, VIDEO_MP4, VIDEO_MKV, VIDEO_REALMEDIA, VIDEO_WEBM, VIDEO_OGV, VIDEO_MPEG, APPLICATION_CLIP, APPLICATION_PSD, APPLICATION_SAI2, APPLICATION_KRITA, APPLICATION_PDF, APPLICATION_ZIP, APPLICATION_RAR, APPLICATION_7Z, AUDIO_M4A, AUDIO_MP3, AUDIO_REALMEDIA, AUDIO_OGG, AUDIO_FLAC, AUDIO_WAVE, AUDIO_TRUEAUDIO, AUDIO_WMA, VIDEO_WMV, AUDIO_MKV, AUDIO_MP4, AUDIO_WAVPACK }
|
||||
|
||||
STORABLE_MIMES = set( SEARCHABLE_MIMES ).union( { APPLICATION_HYDRUS_UPDATE_CONTENT, APPLICATION_HYDRUS_UPDATE_DEFINITIONS } )
|
||||
|
||||
|
@ -736,7 +737,7 @@ AUDIO = { AUDIO_M4A, AUDIO_MP3, AUDIO_OGG, AUDIO_FLAC, AUDIO_WAVE, AUDIO_WMA, AU
|
|||
|
||||
VIDEO = { VIDEO_AVI, VIDEO_FLV, VIDEO_MOV, VIDEO_MP4, VIDEO_WMV, VIDEO_MKV, VIDEO_REALMEDIA, VIDEO_WEBM, VIDEO_OGV, VIDEO_MPEG }
|
||||
|
||||
APPLICATIONS = { APPLICATION_FLASH, APPLICATION_PSD, APPLICATION_CLIP, APPLICATION_SAI2, APPLICATION_KRITA, APPLICATION_PDF, APPLICATION_ZIP, APPLICATION_RAR, APPLICATION_7Z }
|
||||
APPLICATIONS = { IMAGE_SVG, APPLICATION_FLASH, APPLICATION_PSD, APPLICATION_CLIP, APPLICATION_SAI2, APPLICATION_KRITA, APPLICATION_PDF, APPLICATION_ZIP, APPLICATION_RAR, APPLICATION_7Z }
|
||||
|
||||
general_mimetypes_to_mime_groups = {
|
||||
GENERAL_APPLICATION : APPLICATIONS,
|
||||
|
@ -761,7 +762,7 @@ MIMES_THAT_MAY_HAVE_AUDIO = tuple( list( MIMES_THAT_DEFINITELY_HAVE_AUDIO ) + li
|
|||
|
||||
ARCHIVES = { APPLICATION_ZIP, APPLICATION_HYDRUS_ENCRYPTED_ZIP, APPLICATION_RAR, APPLICATION_7Z }
|
||||
|
||||
MIMES_WITH_THUMBNAILS = set( IMAGES ).union( ANIMATIONS ).union( VIDEO ).union( { 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 }
|
||||
|
||||
|
@ -787,6 +788,7 @@ mime_enum_lookup = {
|
|||
'image/webp' : IMAGE_WEBP,
|
||||
'image/tiff' : IMAGE_TIFF,
|
||||
'image/x-icon' : IMAGE_ICON,
|
||||
'image/svg+xml': IMAGE_SVG,
|
||||
'image/vnd.microsoft.icon' : IMAGE_ICON,
|
||||
'image' : IMAGES,
|
||||
'application/x-shockwave-flash' : APPLICATION_FLASH,
|
||||
|
@ -846,6 +848,7 @@ mime_string_lookup = {
|
|||
IMAGE_WEBP : 'webp',
|
||||
IMAGE_TIFF : 'tiff',
|
||||
IMAGE_ICON : 'icon',
|
||||
IMAGE_SVG : 'svg',
|
||||
APPLICATION_FLASH : 'flash',
|
||||
APPLICATION_OCTET_STREAM : 'application/octet-stream',
|
||||
APPLICATION_YAML : 'yaml',
|
||||
|
@ -907,6 +910,7 @@ mime_mimetype_string_lookup = {
|
|||
IMAGE_WEBP : 'image/webp',
|
||||
IMAGE_TIFF : 'image/tiff',
|
||||
IMAGE_ICON : 'image/x-icon',
|
||||
IMAGE_SVG : 'image/svg+xml',
|
||||
APPLICATION_FLASH : 'application/x-shockwave-flash',
|
||||
APPLICATION_OCTET_STREAM : 'application/octet-stream',
|
||||
APPLICATION_YAML : 'application/x-yaml',
|
||||
|
@ -969,6 +973,7 @@ mime_ext_lookup = {
|
|||
IMAGE_WEBP : '.webp',
|
||||
IMAGE_TIFF : '.tiff',
|
||||
IMAGE_ICON : '.ico',
|
||||
IMAGE_SVG : '.svg',
|
||||
APPLICATION_FLASH : '.swf',
|
||||
APPLICATION_OCTET_STREAM : '.bin',
|
||||
APPLICATION_YAML : '.yaml',
|
||||
|
|
|
@ -5,6 +5,7 @@ import struct
|
|||
from hydrus.core import HydrusAudioHandling
|
||||
from hydrus.core import HydrusClipHandling
|
||||
from hydrus.core import HydrusKritaHandling
|
||||
from hydrus.core import HydrusSVGHandling
|
||||
from hydrus.core import HydrusConstants as HC
|
||||
from hydrus.core import HydrusData
|
||||
from hydrus.core import HydrusDocumentHandling
|
||||
|
@ -156,7 +157,7 @@ def GenerateThumbnailBytes( path, target_resolution, mime, duration, num_frames,
|
|||
finally:
|
||||
|
||||
HydrusTemp.CleanUpTempPath( os_file_handle, temp_path )
|
||||
|
||||
|
||||
|
||||
elif mime == HC.APPLICATION_KRITA:
|
||||
|
||||
|
@ -178,7 +179,23 @@ def GenerateThumbnailBytes( path, target_resolution, mime, duration, num_frames,
|
|||
|
||||
HydrusTemp.CleanUpTempPath( os_file_handle, temp_path )
|
||||
|
||||
|
||||
elif mime == HC.IMAGE_SVG:
|
||||
|
||||
try:
|
||||
|
||||
thumbnail_bytes = HydrusSVGHandling.GenerateThumbnailBytesFromSVGPath( path, target_resolution, clip_rect = clip_rect )
|
||||
|
||||
except Exception as e:
|
||||
|
||||
HydrusData.Print( 'Problem generating thumbnail for "{}":'.format( path ) )
|
||||
HydrusData.PrintException( e )
|
||||
|
||||
thumb_path = os.path.join( HC.STATIC_DIR, 'svg.png' )
|
||||
|
||||
thumbnail_bytes = HydrusImageHandling.GenerateThumbnailBytesFromStaticImagePath( thumb_path, target_resolution, HC.IMAGE_PNG, clip_rect = clip_rect )
|
||||
|
||||
|
||||
elif mime == HC.APPLICATION_FLASH:
|
||||
|
||||
( os_file_handle, temp_path ) = HydrusTemp.GetTempPath()
|
||||
|
@ -344,6 +361,10 @@ def GetFileInfo( path, mime = None, ok_to_look_for_hydrus_updates = False ):
|
|||
|
||||
( width, height ) = HydrusKritaHandling.GetKraProperties( path )
|
||||
|
||||
elif mime == HC.IMAGE_SVG:
|
||||
|
||||
( width, height ) = HydrusSVGHandling.GetSVGResolution( path )
|
||||
|
||||
elif mime == HC.APPLICATION_FLASH:
|
||||
|
||||
( ( width, height ), duration, num_frames ) = HydrusFlashHandling.GetFlashProperties( path )
|
||||
|
@ -490,6 +511,9 @@ def GetMime( path, ok_to_look_for_hydrus_updates = False ):
|
|||
|
||||
return HC.TEXT_HTML
|
||||
|
||||
if HydrusText.LooksLikeSVG( bit_to_check ):
|
||||
|
||||
return HC.IMAGE_SVG
|
||||
|
||||
# it is important this goes at the end, because ffmpeg has a billion false positives!
|
||||
# for instance, it once thought some hydrus update files were mpegs
|
||||
|
|
|
@ -879,6 +879,7 @@ def GetThumbnailResolutionAndClipRegion( image_resolution: typing.Tuple[ int, in
|
|||
bounding_height = int( bounding_height * thumbnail_dpr )
|
||||
bounding_width = int( bounding_width * thumbnail_dpr )
|
||||
|
||||
# TODO SVG thumbs should always scale up to the bounding dimensions
|
||||
|
||||
if thumbnail_scale_type == THUMBNAIL_SCALE_DOWN_ONLY:
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@ mimes_to_default_thumbnail_paths[ HC.APPLICATION_PSD ] = os.path.join( HC.STATIC
|
|||
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' )
|
||||
mimes_to_default_thumbnail_paths[ HC.APPLICATION_KRITA ] = os.path.join( HC.STATIC_DIR, 'krita.png' )
|
||||
mimes_to_default_thumbnail_paths[ HC.IMAGE_SVG ] = os.path.join( HC.STATIC_DIR, 'svg.png' )
|
||||
|
||||
for mime in HC.AUDIO:
|
||||
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
from qtpy import QtSvg
|
||||
from qtpy import QtGui as QG
|
||||
from qtpy import QtCore as QC
|
||||
|
||||
from hydrus.core import HydrusExceptions
|
||||
from hydrus.core import HydrusImageHandling
|
||||
|
||||
from hydrus.client.gui import ClientGUIFunctions
|
||||
|
||||
def LoadSVGRenderer(path: str):
|
||||
|
||||
renderer = QtSvg.QSvgRenderer();
|
||||
|
||||
try:
|
||||
renderer.load(path)
|
||||
|
||||
except:
|
||||
|
||||
raise HydrusExceptions.DamagedOrUnusualFileException('Could not load SVG file.')
|
||||
|
||||
if not renderer.isValid():
|
||||
|
||||
raise HydrusExceptions.DamagedOrUnusualFileException('SVG file is invalid!')
|
||||
|
||||
return renderer
|
||||
|
||||
def GenerateThumbnailBytesFromSVGPath(path: str, target_resolution: tuple[int, int], clip_rect = None) -> bytes:
|
||||
|
||||
# TODO handle clipping
|
||||
|
||||
( target_width, target_height ) = target_resolution
|
||||
|
||||
renderer = LoadSVGRenderer(path)
|
||||
|
||||
# Seems to help for some weird floating point dimension SVGs
|
||||
renderer.setAspectRatioMode(QC.Qt.AspectRatioMode.KeepAspectRatio)
|
||||
|
||||
try:
|
||||
|
||||
qt_image = QG.QImage( target_width, target_height, QG.QImage.Format_RGBA8888 )
|
||||
|
||||
qt_image.fill( QC.Qt.transparent )
|
||||
|
||||
painter = QG.QPainter(qt_image)
|
||||
|
||||
renderer.render(painter)
|
||||
|
||||
numpy_image = ClientGUIFunctions.ConvertQtImageToNumPy(qt_image)
|
||||
|
||||
painter.end()
|
||||
|
||||
return HydrusImageHandling.GenerateThumbnailBytesNumPy(numpy_image)
|
||||
|
||||
except:
|
||||
|
||||
raise HydrusExceptions.UnsupportedFileException()
|
||||
|
||||
|
||||
def GetSVGResolution( path: str ):
|
||||
|
||||
renderer = LoadSVGRenderer(path)
|
||||
|
||||
resolution = renderer.defaultSize().toTuple()
|
||||
|
||||
return resolution
|
|
@ -96,11 +96,33 @@ def LooksLikeHTML( file_data ):
|
|||
|
||||
if isinstance( file_data, bytes ):
|
||||
|
||||
search_elements = ( b'<html', b'<HTML', b'<title', b'<TITLE' )
|
||||
search_elements = ( b'<html', b'<HTML', b'<!DOCTYPE html', b'<!DOCTYPE HTML' )
|
||||
|
||||
else:
|
||||
|
||||
search_elements = ( '<html', '<HTML', '<title', '<TITLE' )
|
||||
search_elements = ( '<html', '<HTML', '<!DOCTYPE html', '<!DOCTYPE HTML' )
|
||||
|
||||
|
||||
for s_e in search_elements:
|
||||
|
||||
if s_e in file_data:
|
||||
|
||||
return True
|
||||
|
||||
|
||||
|
||||
return False
|
||||
|
||||
def LooksLikeSVG( file_data ):
|
||||
|
||||
|
||||
if isinstance( file_data, bytes ):
|
||||
|
||||
search_elements = ( b'<svg', b'<SVG', b'<!DOCTYPE svg', b'<!DOCTYPE SVG' )
|
||||
|
||||
else:
|
||||
|
||||
search_elements = ( '<svg', '<SVG', '<!DOCTYPE svg', '<!DOCTYPE SVG' )
|
||||
|
||||
|
||||
for s_e in search_elements:
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 13 KiB |
Loading…
Reference in New Issue