192 lines
4.7 KiB
Python
Executable File
192 lines
4.7 KiB
Python
Executable File
import cStringIO
|
|
import HydrusConstants as HC
|
|
import HydrusExceptions
|
|
import HydrusThreading
|
|
import lz4
|
|
import os
|
|
from PIL import _imaging
|
|
from PIL import Image as PILImage
|
|
import shutil
|
|
import struct
|
|
import threading
|
|
import time
|
|
import traceback
|
|
import HydrusData
|
|
import HydrusGlobals
|
|
import HydrusPaths
|
|
|
|
def ConvertToPngIfBmp( path ):
|
|
|
|
with open( path, 'rb' ) as f: header = f.read( 2 )
|
|
|
|
if header == 'BM':
|
|
|
|
( os_file_handle, temp_path ) = HydrusPaths.GetTempPath()
|
|
|
|
try:
|
|
|
|
with open( path, 'rb' ) as f_source:
|
|
|
|
with open( temp_path, 'wb' ) as f_dest:
|
|
|
|
HydrusPaths.CopyFileLikeToFileLike( f_source, f_dest )
|
|
|
|
|
|
|
|
pil_image = GeneratePILImage( temp_path )
|
|
|
|
pil_image.save( path, 'PNG' )
|
|
|
|
finally:
|
|
|
|
HydrusPaths.CleanUpTempPath( os_file_handle, temp_path )
|
|
|
|
|
|
|
|
def EfficientlyResizePILImage( pil_image, ( target_x, target_y ) ):
|
|
|
|
( im_x, im_y ) = pil_image.size
|
|
|
|
if target_x >= im_x and target_y >= im_y: return pil_image
|
|
|
|
#if pil_image.mode == 'RGB': # low quality resize screws up alpha channel!
|
|
#
|
|
# if im_x > 2 * target_x and im_y > 2 * target_y: pil_image.thumbnail( ( 2 * target_x, 2 * target_y ), PILImage.NEAREST )
|
|
#
|
|
|
|
return pil_image.resize( ( target_x, target_y ), PILImage.ANTIALIAS )
|
|
|
|
def EfficientlyThumbnailPILImage( pil_image, ( target_x, target_y ) ):
|
|
|
|
( im_x, im_y ) = pil_image.size
|
|
|
|
#if pil_image.mode == 'RGB': # low quality resize screws up alpha channel!
|
|
#
|
|
# if im_x > 2 * target_x or im_y > 2 * target_y: pil_image.thumbnail( ( 2 * target_x, 2 * target_y ), PILImage.NEAREST )
|
|
#
|
|
|
|
if im_x > target_x or im_y > target_y:
|
|
|
|
pil_image.thumbnail( ( target_x, target_y ), PILImage.ANTIALIAS )
|
|
|
|
|
|
def GeneratePILImage( path ):
|
|
|
|
pil_image = PILImage.open( path )
|
|
|
|
if pil_image is None:
|
|
|
|
raise Exception( 'The file at ' + path + ' could not be rendered!' )
|
|
|
|
|
|
return pil_image
|
|
|
|
def GeneratePILImageFromNumpyImage( numpy_image ):
|
|
|
|
( h, w, depth ) = numpy_image.shape
|
|
|
|
if depth == 3: format = 'RGB'
|
|
elif depth == 4: format = 'RGBA'
|
|
|
|
pil_image = PILImage.frombytes( format, ( w, h ), numpy_image.data )
|
|
|
|
return pil_image
|
|
|
|
def GetGIFFrameDurations( path ):
|
|
|
|
pil_image = GeneratePILImage( path )
|
|
|
|
frame_durations = []
|
|
|
|
i = 0
|
|
|
|
while True:
|
|
|
|
try: pil_image.seek( i )
|
|
except: break
|
|
|
|
if 'duration' not in pil_image.info:
|
|
|
|
duration = 83 # Set a 12 fps default when duration is missing or too funky to extract. most stuff looks ok at this.
|
|
|
|
else:
|
|
|
|
duration = pil_image.info[ 'duration' ]
|
|
|
|
# In the gif frame header, 10 is stored as 1ms. This 1 is commonly as utterly wrong as 0.
|
|
if duration in ( 0, 10 ):
|
|
|
|
duration = 80
|
|
|
|
|
|
|
|
frame_durations.append( duration )
|
|
|
|
i += 1
|
|
|
|
|
|
return frame_durations
|
|
|
|
def GetImageProperties( path ):
|
|
|
|
( ( width, height ), num_frames ) = GetResolutionAndNumFrames( path )
|
|
|
|
if num_frames > 1:
|
|
|
|
durations = GetGIFFrameDurations( path )
|
|
|
|
duration = sum( durations )
|
|
|
|
else:
|
|
|
|
duration = None
|
|
num_frames = None
|
|
|
|
|
|
return ( ( width, height ), duration, num_frames )
|
|
|
|
def GetResolutionAndNumFrames( path ):
|
|
|
|
pil_image = GeneratePILImage( path )
|
|
|
|
( x, y ) = pil_image.size
|
|
|
|
try:
|
|
|
|
pil_image.seek( 1 )
|
|
pil_image.seek( 0 )
|
|
|
|
num_frames = 1
|
|
|
|
while True:
|
|
|
|
try:
|
|
|
|
pil_image.seek( pil_image.tell() + 1 )
|
|
num_frames += 1
|
|
|
|
except: break
|
|
|
|
|
|
except: num_frames = 1
|
|
|
|
return ( ( x, y ), num_frames )
|
|
|
|
def GetThumbnailResolution( ( im_x, im_y ), ( target_x, target_y ) ):
|
|
|
|
im_x = float( im_x )
|
|
im_y = float( im_y )
|
|
|
|
target_x = float( target_x )
|
|
target_y = float( target_y )
|
|
|
|
x_ratio = im_x / target_x
|
|
y_ratio = im_y / target_y
|
|
|
|
ratio_to_use = max( x_ratio, y_ratio )
|
|
|
|
target_x = int( im_x / ratio_to_use )
|
|
target_y = int( im_y / ratio_to_use )
|
|
|
|
return ( target_x, target_y )
|
|
|