Add support for procreate file format (#1425)
* Add function to get zip as Path and use it to avoid temp file for krita * Add support for procreate format
This commit is contained in:
parent
a46d6f1790
commit
785e37345f
|
@ -23,4 +23,6 @@ def ReadSingleFileFromZip( path_to_zip, filename_to_extract ):
|
|||
return reader.read()
|
||||
|
||||
|
||||
|
||||
def GetZipAsPath( path_to_zip, path_in_zip="" ):
|
||||
|
||||
return zipfile.Path( path_to_zip, at=path_in_zip )
|
||||
|
|
|
@ -728,6 +728,7 @@ IMAGE_AVIF = 65
|
|||
IMAGE_AVIF_SEQUENCE = 66
|
||||
UNDETERMINED_GIF = 67
|
||||
IMAGE_GIF = 68
|
||||
APPLICATION_PROCREATE = 69
|
||||
IMAGE_QOI = 70
|
||||
APPLICATION_OCTET_STREAM = 100
|
||||
APPLICATION_UNKNOWN = 101
|
||||
|
@ -774,6 +775,7 @@ SEARCHABLE_MIMES = {
|
|||
APPLICATION_SAI2,
|
||||
APPLICATION_KRITA,
|
||||
APPLICATION_XCF,
|
||||
APPLICATION_PROCREATE,
|
||||
APPLICATION_PDF,
|
||||
APPLICATION_ZIP,
|
||||
APPLICATION_RAR,
|
||||
|
@ -869,7 +871,8 @@ IMAGE_PROJECT_FILES = [
|
|||
APPLICATION_SAI2,
|
||||
APPLICATION_KRITA,
|
||||
IMAGE_SVG,
|
||||
APPLICATION_XCF
|
||||
APPLICATION_XCF,
|
||||
APPLICATION_PROCREATE
|
||||
]
|
||||
|
||||
ARCHIVES = [
|
||||
|
@ -913,7 +916,7 @@ PIL_HEIF_MIMES = {
|
|||
MIMES_THAT_DEFINITELY_HAVE_AUDIO = tuple( [ APPLICATION_FLASH ] + list( AUDIO ) )
|
||||
MIMES_THAT_MAY_HAVE_AUDIO = tuple( list( MIMES_THAT_DEFINITELY_HAVE_AUDIO ) + list( VIDEO ) )
|
||||
|
||||
APPLICATIONS_WITH_THUMBNAILS = set( { IMAGE_SVG, APPLICATION_FLASH, APPLICATION_CLIP, APPLICATION_KRITA } ).union( VIEWABLE_IMAGE_PROJECT_FILES )
|
||||
APPLICATIONS_WITH_THUMBNAILS = set( { IMAGE_SVG, APPLICATION_FLASH, APPLICATION_CLIP, APPLICATION_KRITA, APPLICATION_PROCREATE } ).union( VIEWABLE_IMAGE_PROJECT_FILES )
|
||||
|
||||
MIMES_WITH_THUMBNAILS = set( IMAGES ).union( ANIMATIONS ).union( VIDEO ).union( APPLICATIONS_WITH_THUMBNAILS )
|
||||
|
||||
|
@ -955,9 +958,10 @@ mime_enum_lookup = {
|
|||
'application/x-photoshop' : APPLICATION_PSD,
|
||||
'image/vnd.adobe.photoshop' : APPLICATION_PSD,
|
||||
'application/vnd.adobe.photoshop' : APPLICATION_PSD,
|
||||
'application/clip' : APPLICATION_CLIP,
|
||||
'application/sai2': APPLICATION_SAI2,
|
||||
'application/clip' : APPLICATION_CLIP, # made up
|
||||
'application/sai2': APPLICATION_SAI2, # made up
|
||||
'application/x-krita': APPLICATION_KRITA,
|
||||
'application/x-procreate': APPLICATION_PROCREATE, # made up
|
||||
'image/x-xcf' : APPLICATION_XCF,
|
||||
'application/octet-stream' : APPLICATION_OCTET_STREAM,
|
||||
'application/x-yaml' : APPLICATION_YAML,
|
||||
|
@ -1031,6 +1035,7 @@ mime_string_lookup = {
|
|||
APPLICATION_SAI2 : 'sai2',
|
||||
APPLICATION_KRITA : 'krita',
|
||||
APPLICATION_XCF : 'xcf',
|
||||
APPLICATION_PROCREATE : 'procreate',
|
||||
APPLICATION_ZIP : 'zip',
|
||||
APPLICATION_RAR : 'rar',
|
||||
APPLICATION_7Z : '7z',
|
||||
|
@ -1103,10 +1108,11 @@ mime_mimetype_string_lookup = {
|
|||
APPLICATION_CBOR : 'application/cbor',
|
||||
APPLICATION_PDF : 'application/pdf',
|
||||
APPLICATION_PSD : 'image/vnd.adobe.photoshop',
|
||||
APPLICATION_CLIP : 'application/clip',
|
||||
APPLICATION_SAI2: 'application/sai2',
|
||||
APPLICATION_CLIP : 'application/clip', # made up
|
||||
APPLICATION_SAI2: 'application/sai2', # made up
|
||||
APPLICATION_KRITA: 'application/x-krita',
|
||||
APPLICATION_XCF : 'image/x-xcf',
|
||||
APPLICATION_PROCREATE : 'application/x-procreate', # made up
|
||||
APPLICATION_ZIP : 'application/zip',
|
||||
APPLICATION_RAR : 'application/vnd.rar',
|
||||
APPLICATION_7Z : 'application/x-7z-compressed',
|
||||
|
@ -1181,6 +1187,7 @@ mime_ext_lookup = {
|
|||
APPLICATION_SAI2: '.sai2',
|
||||
APPLICATION_KRITA: '.kra',
|
||||
APPLICATION_XCF : '.xcf',
|
||||
APPLICATION_PROCREATE : '.procreate',
|
||||
APPLICATION_ZIP : '.zip',
|
||||
APPLICATION_RAR : '.rar',
|
||||
APPLICATION_7Z : '.7z',
|
||||
|
|
|
@ -12,6 +12,7 @@ from hydrus.core import HydrusExceptions
|
|||
from hydrus.core import HydrusFlashHandling
|
||||
from hydrus.core import HydrusImageHandling
|
||||
from hydrus.core import HydrusKritaHandling
|
||||
from hydrus.core import HydrusProcreateHandling
|
||||
from hydrus.core import HydrusPaths
|
||||
from hydrus.core import HydrusSerialisable
|
||||
from hydrus.core import HydrusSVGHandling
|
||||
|
@ -184,6 +185,25 @@ def GenerateThumbnailBytes( path, target_resolution, mime, duration, num_frames,
|
|||
|
||||
HydrusTemp.CleanUpTempPath( os_file_handle, temp_path )
|
||||
|
||||
elif mime == HC.APPLICATION_PROCREATE:
|
||||
|
||||
( os_file_handle, temp_path ) = HydrusTemp.GetTempPath()
|
||||
|
||||
try:
|
||||
|
||||
HydrusProcreateHandling.ExtractZippedThumbnailToPath( path, temp_path )
|
||||
|
||||
thumbnail_bytes = HydrusImageHandling.GenerateThumbnailBytesFromStaticImagePath( temp_path, target_resolution, HC.IMAGE_PNG, clip_rect = clip_rect )
|
||||
|
||||
except Exception as e:
|
||||
|
||||
thumb_path = os.path.join( HC.STATIC_DIR, 'procreate.png' )
|
||||
|
||||
thumbnail_bytes = HydrusImageHandling.GenerateThumbnailBytesFromStaticImagePath( thumb_path, target_resolution, HC.IMAGE_PNG, clip_rect = clip_rect )
|
||||
|
||||
finally:
|
||||
|
||||
HydrusTemp.CleanUpTempPath( os_file_handle, temp_path )
|
||||
|
||||
elif mime == HC.IMAGE_SVG:
|
||||
|
||||
|
@ -389,6 +409,10 @@ def GetFileInfo( path, mime = None, ok_to_look_for_hydrus_updates = False ):
|
|||
elif mime == HC.APPLICATION_KRITA:
|
||||
|
||||
( width, height ) = HydrusKritaHandling.GetKraProperties( path )
|
||||
|
||||
elif mime == HC.APPLICATION_PROCREATE:
|
||||
|
||||
( width, height ) = HydrusProcreateHandling.GetProcreateResolution( path )
|
||||
|
||||
elif mime == HC.IMAGE_SVG:
|
||||
|
||||
|
@ -527,6 +551,10 @@ def GetMime( path, ok_to_look_for_hydrus_updates = False ):
|
|||
if HydrusKritaHandling.ZipLooksLikeAKrita( path ):
|
||||
|
||||
return HC.APPLICATION_KRITA
|
||||
|
||||
elif HydrusProcreateHandling.ZipLooksLikeProcreate( path ):
|
||||
|
||||
return HC.APPLICATION_PROCREATE
|
||||
|
||||
else:
|
||||
|
||||
|
|
|
@ -34,8 +34,6 @@ def ExtractZippedImageToPath( path_to_zip, temp_path_file ):
|
|||
# TODO: animation and frame stuff which is also in the maindoc.xml
|
||||
def GetKraProperties( path ):
|
||||
|
||||
( os_file_handle, maindoc_xml ) = HydrusTemp.GetTempPath()
|
||||
|
||||
DOCUMENT_INFO_FILE = "maindoc.xml"
|
||||
|
||||
# TODO: probably actually parse the xml instead of using regex
|
||||
|
@ -46,9 +44,7 @@ def GetKraProperties( path ):
|
|||
|
||||
try:
|
||||
|
||||
HydrusArchiveHandling.ExtractSingleFileFromZip( path, DOCUMENT_INFO_FILE, maindoc_xml )
|
||||
|
||||
with open(maindoc_xml, "r") as reader:
|
||||
with HydrusArchiveHandling.GetZipAsPath( path, DOCUMENT_INFO_FILE ).open('r') as reader:
|
||||
|
||||
for line in reader:
|
||||
|
||||
|
@ -75,11 +71,7 @@ def GetKraProperties( path ):
|
|||
except KeyError:
|
||||
|
||||
raise HydrusExceptions.DamagedOrUnusualFileException( f'This krita file had no {DOCUMENT_INFO_FILE}, so no information could be extracted!' )
|
||||
|
||||
finally:
|
||||
|
||||
HydrusTemp.CleanUpTempPath( os_file_handle, maindoc_xml )
|
||||
|
||||
|
||||
|
||||
return width, height
|
||||
|
||||
|
|
|
@ -26,6 +26,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.APPLICATION_PROCREATE ] = os.path.join( HC.STATIC_DIR, 'procreate.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,86 @@
|
|||
from hydrus.core import HydrusArchiveHandling
|
||||
from hydrus.core import HydrusExceptions
|
||||
import plistlib
|
||||
|
||||
# Mostly based on https://github.com/jaromvogel/ProcreateViewer/blob/master/ProcreatePython/ProcreateImageData.py
|
||||
|
||||
PROCREATE_THUMBNAIL_FILE_PATH = 'QuickLook/Thumbnail.png'
|
||||
PROCREATE_DOCUMENT_ARCHIVE = 'Document.archive'
|
||||
# object key in plist to start from (trunk)
|
||||
PROCREATE_PROJECT_KEY = 1
|
||||
|
||||
def ExtractZippedThumbnailToPath( path_to_zip, temp_path_file ):
|
||||
|
||||
try:
|
||||
|
||||
HydrusArchiveHandling.ExtractSingleFileFromZip( path_to_zip, PROCREATE_THUMBNAIL_FILE_PATH, temp_path_file )
|
||||
|
||||
except KeyError:
|
||||
|
||||
raise HydrusExceptions.DamagedOrUnusualFileException( f'This procreate file had no thumbnail file!' )
|
||||
|
||||
|
||||
def GetProcreatePlist( path ):
|
||||
|
||||
plist_file = HydrusArchiveHandling.GetZipAsPath( path, PROCREATE_DOCUMENT_ARCHIVE )
|
||||
|
||||
if not plist_file.exists():
|
||||
|
||||
raise HydrusExceptions.DamagedOrUnusualFileException('Procreate file has no plist!')
|
||||
|
||||
with HydrusArchiveHandling.GetZipAsPath( path, PROCREATE_DOCUMENT_ARCHIVE ).open('rb') as document:
|
||||
|
||||
return plistlib.load(document)
|
||||
|
||||
|
||||
def ZipLooksLikeProcreate( path ) -> bool:
|
||||
|
||||
try:
|
||||
|
||||
document = GetProcreatePlist( path )
|
||||
|
||||
objects = document['$objects']
|
||||
|
||||
class_pointer = objects[PROCREATE_PROJECT_KEY]['$class']
|
||||
|
||||
class_name = objects[class_pointer]['$classname']
|
||||
|
||||
return class_name == 'SilicaDocument'
|
||||
|
||||
except:
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def GetProcreateResolution( path ):
|
||||
|
||||
# TODO: animation stuff from plist
|
||||
|
||||
document = GetProcreatePlist( path )
|
||||
|
||||
objects = document['$objects']
|
||||
|
||||
dimension_pointer = objects[PROCREATE_PROJECT_KEY]['size'].data
|
||||
|
||||
# eg '{2894, 4093}'
|
||||
size_string = objects[dimension_pointer]
|
||||
|
||||
size = size_string.strip('{').strip('}').split(', ')
|
||||
|
||||
orientation = objects[PROCREATE_PROJECT_KEY]['orientation']
|
||||
|
||||
if orientation in [3,4]:
|
||||
|
||||
# canvas is rotated 90 or -90 degrees
|
||||
|
||||
height = size[1]
|
||||
|
||||
width = size[0]
|
||||
|
||||
else:
|
||||
|
||||
height = size[0]
|
||||
|
||||
width = size[1]
|
||||
|
||||
return int(width), int(height)
|
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
Loading…
Reference in New Issue