hydrus/include/ClientRendering.py

752 lines
22 KiB
Python
Raw Normal View History

2019-01-09 22:59:03 +00:00
from . import ClientFiles
from . import ClientImageHandling
from . import ClientVideoHandling
from . import HydrusConstants as HC
from . import HydrusData
from . import HydrusExceptions
from . import HydrusImageHandling
from . import HydrusGlobals as HG
from . import HydrusThreading
from . import HydrusVideoHandling
2017-03-15 20:13:04 +00:00
import os
2015-08-05 18:42:35 +00:00
import threading
import time
import wx
2018-01-17 22:52:10 +00:00
LZ4_OK = False
try:
2018-08-22 21:10:59 +00:00
import lz4
2018-01-17 22:52:10 +00:00
import lz4.block
LZ4_OK = True
2018-08-22 21:10:59 +00:00
except Exception as e: # ImportError wasn't enough here as Linux went up the shoot with a __version__ doesn't exist bs
2018-01-17 22:52:10 +00:00
pass
2018-12-05 22:35:30 +00:00
def FrameIndexOutOfRange( index, range_start, range_end ):
before_start = index < range_start
after_end = range_end < index
if range_start < range_end:
if before_start or after_end:
return True
else:
if after_end and before_start:
return True
return False
2019-04-03 22:45:57 +00:00
def GenerateHydrusBitmap( path, mime, compressed = True ):
2015-08-05 18:42:35 +00:00
2017-08-23 21:34:25 +00:00
numpy_image = ClientImageHandling.GenerateNumpyImage( path, mime )
2016-05-11 18:16:39 +00:00
return GenerateHydrusBitmapFromNumPyImage( numpy_image, compressed = compressed )
2015-08-05 18:42:35 +00:00
def GenerateHydrusBitmapFromNumPyImage( numpy_image, compressed = True ):
( y, x, depth ) = numpy_image.shape
2018-05-30 20:13:21 +00:00
return HydrusBitmap( numpy_image.data, ( x, y ), depth, compressed = compressed )
2015-08-05 18:42:35 +00:00
def GenerateHydrusBitmapFromPILImage( pil_image, compressed = True ):
2016-06-29 19:55:46 +00:00
pil_image = HydrusImageHandling.Dequantize( pil_image )
if pil_image.mode == 'RGBA':
2015-08-05 18:42:35 +00:00
2018-05-30 20:13:21 +00:00
depth = 4
2015-08-05 18:42:35 +00:00
2016-06-29 19:55:46 +00:00
elif pil_image.mode == 'RGB':
2015-08-05 18:42:35 +00:00
2018-05-30 20:13:21 +00:00
depth = 3
2015-08-05 18:42:35 +00:00
2018-05-30 20:13:21 +00:00
return HydrusBitmap( pil_image.tobytes(), pil_image.size, depth, compressed = compressed )
2015-08-05 18:42:35 +00:00
2016-09-21 19:54:04 +00:00
class ImageRenderer( object ):
def __init__( self, media ):
self._media = media
self._numpy_image = None
2017-08-23 21:34:25 +00:00
self._hash = self._media.GetHash()
self._mime = self._media.GetMime()
2016-09-21 19:54:04 +00:00
2017-06-28 20:23:21 +00:00
client_files_manager = HG.client_controller.client_files_manager
2016-09-21 19:54:04 +00:00
2017-08-23 21:34:25 +00:00
self._path = client_files_manager.GetFilePath( self._hash, self._mime )
2016-09-21 19:54:04 +00:00
2017-05-10 21:33:58 +00:00
HG.client_controller.CallToThread( self._Initialise )
2016-09-21 19:54:04 +00:00
def _Initialise( self ):
2017-08-23 21:34:25 +00:00
self._numpy_image = ClientImageHandling.GenerateNumpyImage( self._path, self._mime )
2016-09-21 19:54:04 +00:00
def GetEstimatedMemoryFootprint( self ):
if self._numpy_image is None:
( width, height ) = self.GetResolution()
return width * height * 3
else:
( height, width, depth ) = self._numpy_image.shape
return height * width * depth
def GetHash( self ): return self._media.GetHash()
def GetNumFrames( self ): return self._media.GetNumFrames()
def GetResolution( self ): return self._media.GetResolution()
def GetWXBitmap( self, target_resolution = None ):
# add region param to this to allow clipping before resize
if target_resolution is None:
wx_numpy_image = self._numpy_image
else:
2019-03-27 22:01:02 +00:00
wx_numpy_image = ClientImageHandling.ResizeNumpyImageForMediaViewer( self._media.GetMime(), self._numpy_image, target_resolution )
2016-09-21 19:54:04 +00:00
( wx_height, wx_width, wx_depth ) = wx_numpy_image.shape
wx_data = wx_numpy_image.data
if wx_depth == 3:
2018-01-03 22:37:30 +00:00
return wx.Bitmap.FromBuffer( wx_width, wx_height, wx_data )
2016-09-21 19:54:04 +00:00
else:
2018-01-03 22:37:30 +00:00
return wx.Bitmap.FromBufferRGBA( wx_width, wx_height, wx_data )
2016-09-21 19:54:04 +00:00
def IsReady( self ):
return self._numpy_image is not None
2015-08-05 18:42:35 +00:00
class RasterContainer( object ):
def __init__( self, media, target_resolution = None ):
if target_resolution is None: target_resolution = media.GetResolution()
( width, height ) = target_resolution
2016-04-06 19:52:45 +00:00
if width == 0 or height == 0:
target_resolution = ( 100, 100 )
2015-08-05 18:42:35 +00:00
self._media = media
2016-04-06 19:52:45 +00:00
( media_width, media_height ) = self._media.GetResolution()
( target_width, target_height ) = target_resolution
if target_width > media_width or target_height > media_height:
target_resolution = self._media.GetResolution()
2015-08-05 18:42:35 +00:00
self._target_resolution = target_resolution
2016-04-06 19:52:45 +00:00
( target_width, target_height ) = target_resolution
2015-08-05 18:42:35 +00:00
hash = self._media.GetHash()
mime = self._media.GetMime()
2017-06-28 20:23:21 +00:00
client_files_manager = HG.client_controller.client_files_manager
2015-12-02 22:32:18 +00:00
self._path = client_files_manager.GetFilePath( hash, mime )
2015-08-05 18:42:35 +00:00
2019-01-09 22:59:03 +00:00
width_zoom = target_width / media_width
height_zoom = target_height / media_height
2015-08-05 18:42:35 +00:00
self._zoom = min( ( width_zoom, height_zoom ) )
2019-01-09 22:59:03 +00:00
if self._zoom > 1.0:
self._zoom = 1.0
2015-08-05 18:42:35 +00:00
class RasterContainerVideo( RasterContainer ):
def __init__( self, media, target_resolution = None, init_position = 0 ):
RasterContainer.__init__( self, media, target_resolution )
2016-10-19 20:02:56 +00:00
self._init_position = init_position
self._initialised = False
2019-03-06 23:06:22 +00:00
self._renderer = None
2015-08-05 18:42:35 +00:00
self._frames = {}
2018-09-05 20:52:32 +00:00
2015-08-05 18:42:35 +00:00
self._buffer_start_index = -1
self._buffer_end_index = -1
2016-07-27 21:53:34 +00:00
self._stop = False
2015-08-05 18:42:35 +00:00
2016-08-03 22:15:54 +00:00
self._render_event = threading.Event()
2015-08-05 18:42:35 +00:00
( x, y ) = self._target_resolution
2017-12-06 22:06:56 +00:00
new_options = HG.client_controller.new_options
2016-07-27 21:53:34 +00:00
video_buffer_size_mb = new_options.GetInteger( 'video_buffer_size_mb' )
duration = self._media.GetDuration()
2018-09-05 20:52:32 +00:00
num_frames_in_video = self._media.GetNumFrames()
2016-07-27 21:53:34 +00:00
2018-10-24 21:34:02 +00:00
if duration is None or duration == 0:
2019-01-09 22:59:03 +00:00
message = 'The file with hash ' + media.GetHash().hex() + ', had an invalid duration.'
2018-10-24 21:34:02 +00:00
message += os.linesep * 2
message += 'You may wish to try regenerating its metadata through the advanced mode right-click menu.'
HydrusData.ShowText( message )
duration = 1.0
2018-09-05 20:52:32 +00:00
if num_frames_in_video is None or num_frames_in_video == 0:
2017-03-15 20:13:04 +00:00
2019-01-09 22:59:03 +00:00
message = 'The file with hash ' + media.GetHash().hex() + ', had an invalid number of frames.'
2017-03-15 20:13:04 +00:00
message += os.linesep * 2
2018-10-24 21:34:02 +00:00
message += 'You may wish to try regenerating its metadata through the advanced mode right-click menu.'
2017-03-15 20:13:04 +00:00
HydrusData.ShowText( message )
2018-09-05 20:52:32 +00:00
num_frames_in_video = 1
2017-03-15 20:13:04 +00:00
2019-01-09 22:59:03 +00:00
self._average_frame_duration = duration / num_frames_in_video
2016-07-27 21:53:34 +00:00
2019-01-09 22:59:03 +00:00
frame_buffer_length = ( video_buffer_size_mb * 1024 * 1024 ) // ( x * y * 3 )
2016-07-27 21:53:34 +00:00
# if we can't buffer the whole vid, then don't have a clunky massive buffer
2018-09-05 20:52:32 +00:00
max_streaming_buffer_size = max( 48, int( num_frames_in_video / ( duration / 3.0 ) ) ) # 48 or 3 seconds
2016-08-03 22:15:54 +00:00
2018-09-05 20:52:32 +00:00
if max_streaming_buffer_size < frame_buffer_length and frame_buffer_length < num_frames_in_video:
2016-07-27 21:53:34 +00:00
2016-08-03 22:15:54 +00:00
frame_buffer_length = max_streaming_buffer_size
2016-07-27 21:53:34 +00:00
2015-08-05 18:42:35 +00:00
2019-01-09 22:59:03 +00:00
self._num_frames_backwards = frame_buffer_length * 2 // 3
self._num_frames_forwards = frame_buffer_length // 3
2015-08-05 18:42:35 +00:00
2018-09-05 20:52:32 +00:00
self._lock = threading.Lock()
2015-08-05 18:42:35 +00:00
2016-08-03 22:15:54 +00:00
self._last_index_rendered = -1
2016-07-27 21:53:34 +00:00
self._next_render_index = -1
2015-08-05 18:42:35 +00:00
self._rendered_first_frame = False
2018-09-05 20:52:32 +00:00
self._ideal_next_frame = 0
2015-08-05 18:42:35 +00:00
2017-05-10 21:33:58 +00:00
HG.client_controller.CallToThread( self.THREADRender )
2016-08-03 22:15:54 +00:00
2015-08-05 18:42:35 +00:00
2018-09-05 20:52:32 +00:00
def _HasFrame( self, index ):
return index in self._frames
def _IndexInRange( self, index, range_start, range_end ):
2018-12-05 22:35:30 +00:00
return not FrameIndexOutOfRange( index, range_start, range_end )
2015-08-05 18:42:35 +00:00
2016-07-27 21:53:34 +00:00
def _MaintainBuffer( self ):
2019-01-09 22:59:03 +00:00
deletees = [ index for index in list(self._frames.keys()) if FrameIndexOutOfRange( index, self._buffer_start_index, self._buffer_end_index ) ]
2016-08-03 22:15:54 +00:00
2018-09-05 20:52:32 +00:00
for i in deletees:
2016-08-03 22:15:54 +00:00
2018-09-05 20:52:32 +00:00
del self._frames[ i ]
2016-10-19 20:02:56 +00:00
2016-08-03 22:15:54 +00:00
def THREADRender( self ):
2015-08-05 18:42:35 +00:00
2016-10-19 20:02:56 +00:00
hash = self._media.GetHash()
mime = self._media.GetMime()
duration = self._media.GetDuration()
2018-09-05 20:52:32 +00:00
num_frames_in_video = self._media.GetNumFrames()
2015-08-05 18:42:35 +00:00
2017-06-28 20:23:21 +00:00
client_files_manager = HG.client_controller.client_files_manager
2016-10-19 20:02:56 +00:00
if self._media.GetMime() == HC.IMAGE_GIF:
self._durations = HydrusImageHandling.GetGIFFrameDurations( self._path )
2018-09-05 20:52:32 +00:00
self._renderer = ClientVideoHandling.GIFRenderer( self._path, num_frames_in_video, self._target_resolution )
2016-10-19 20:02:56 +00:00
else:
2018-09-05 20:52:32 +00:00
self._renderer = HydrusVideoHandling.VideoRendererFFMPEG( self._path, mime, duration, num_frames_in_video, self._target_resolution )
2016-10-19 20:02:56 +00:00
self.GetReadyForFrame( self._init_position )
2018-09-05 20:52:32 +00:00
with self._lock:
self._initialised = True
2015-08-05 18:42:35 +00:00
while True:
2017-05-10 21:33:58 +00:00
if self._stop or HG.view_shutdown:
2016-07-27 21:53:34 +00:00
2019-03-06 23:06:22 +00:00
self._renderer.Stop()
self._renderer = None
with self._lock:
self._frames = {}
2016-07-27 21:53:34 +00:00
return
2015-08-05 18:42:35 +00:00
2018-09-05 20:52:32 +00:00
#
with self._lock:
# lets see if we should move the renderer to a new position
2018-12-05 22:35:30 +00:00
next_render_is_out_of_buffer = FrameIndexOutOfRange( self._next_render_index, self._buffer_start_index, self._buffer_end_index )
2018-09-05 20:52:32 +00:00
buffer_not_fully_rendered = self._last_index_rendered != self._buffer_end_index
currently_rendering_out_of_buffer = next_render_is_out_of_buffer and buffer_not_fully_rendered
will_render_ideal_frame_soon = self._IndexInRange( self._next_render_index, self._buffer_start_index, self._ideal_next_frame )
need_ideal_next_frame = not self._HasFrame( self._ideal_next_frame )
will_not_get_to_ideal_frame = need_ideal_next_frame and not will_render_ideal_frame_soon
if currently_rendering_out_of_buffer or will_not_get_to_ideal_frame:
# we cannot get to the ideal next frame, so we need to rewind/reposition
self._renderer.set_position( self._buffer_start_index )
self._last_index_rendered = -1
self._next_render_index = self._buffer_start_index
#
need_to_render = self._last_index_rendered != self._buffer_end_index
2016-10-19 20:02:56 +00:00
2018-09-05 20:52:32 +00:00
if need_to_render:
2015-08-05 18:42:35 +00:00
2018-09-05 20:52:32 +00:00
with self._lock:
2015-08-05 18:42:35 +00:00
self._rendered_first_frame = True
frame_index = self._next_render_index # keep this before the get call, as it increments in a clock arithmetic way afterwards
2016-07-06 21:13:15 +00:00
try:
numpy_image = self._renderer.read_frame()
2015-08-05 18:42:35 +00:00
except Exception as e:
HydrusData.ShowException( e )
2016-07-27 21:53:34 +00:00
return
2015-08-05 18:42:35 +00:00
2016-07-06 21:13:15 +00:00
finally:
2016-08-03 22:15:54 +00:00
self._last_index_rendered = frame_index
2018-09-05 20:52:32 +00:00
self._next_render_index = ( self._next_render_index + 1 ) % num_frames_in_video
2016-07-06 21:13:15 +00:00
2015-08-05 18:42:35 +00:00
2016-08-03 22:15:54 +00:00
2018-09-05 20:52:32 +00:00
with self._lock:
2016-08-03 22:15:54 +00:00
2018-09-05 20:52:32 +00:00
if self._next_render_index == 0 and self._buffer_end_index != num_frames_in_video - 1:
2016-08-03 22:15:54 +00:00
2018-09-05 20:52:32 +00:00
# we need to rewind renderer
2016-08-03 22:15:54 +00:00
2018-09-05 20:52:32 +00:00
self._renderer.set_position( 0 )
2016-08-03 22:15:54 +00:00
2018-09-05 20:52:32 +00:00
self._last_index_rendered = -1
should_save_frame = not self._HasFrame( frame_index )
2016-08-03 22:15:54 +00:00
2018-09-05 20:52:32 +00:00
if should_save_frame:
2016-08-03 22:15:54 +00:00
2015-08-05 18:42:35 +00:00
frame = GenerateHydrusBitmapFromNumPyImage( numpy_image, compressed = False )
2018-09-05 20:52:32 +00:00
with self._lock:
2016-07-27 21:53:34 +00:00
self._frames[ frame_index ] = frame
2018-09-05 20:52:32 +00:00
self._MaintainBuffer()
2016-07-06 21:13:15 +00:00
2016-08-03 22:15:54 +00:00
2018-09-05 20:52:32 +00:00
with self._lock:
2019-03-06 23:06:22 +00:00
work_still_to_do = self._last_index_rendered != self._buffer_end_index
2018-09-05 20:52:32 +00:00
2019-03-06 23:06:22 +00:00
if work_still_to_do:
2016-08-03 22:15:54 +00:00
2019-03-06 23:06:22 +00:00
time.sleep( 0.0001 )
2016-08-03 22:15:54 +00:00
2016-07-06 21:13:15 +00:00
else:
2016-08-03 22:15:54 +00:00
half_a_frame = ( self._average_frame_duration / 1000.0 ) * 0.5
2016-07-27 21:53:34 +00:00
2018-09-05 20:52:32 +00:00
sleep_duration = min( 0.1, half_a_frame ) # for 10s-long 3-frame gifs, wew
time.sleep( sleep_duration ) # just so we don't spam cpu
2015-08-05 18:42:35 +00:00
2016-07-27 21:53:34 +00:00
else:
2016-08-03 22:15:54 +00:00
self._render_event.wait( 1 )
2016-07-27 21:53:34 +00:00
2016-08-03 22:15:54 +00:00
self._render_event.clear()
2016-07-27 21:53:34 +00:00
2016-07-06 21:13:15 +00:00
2015-08-05 18:42:35 +00:00
2016-08-03 22:15:54 +00:00
def GetBufferIndices( self ):
if self._last_index_rendered == -1:
return None
else:
return ( self._buffer_start_index, self._last_index_rendered, self._buffer_end_index )
2015-08-05 18:42:35 +00:00
def GetDuration( self, index ):
2017-06-28 20:23:21 +00:00
if self._media.GetMime() == HC.IMAGE_GIF:
return self._durations[ index ]
else:
return self._average_frame_duration
2015-08-05 18:42:35 +00:00
def GetFrame( self, index ):
2018-09-05 20:52:32 +00:00
with self._lock:
2016-07-27 21:53:34 +00:00
frame = self._frames[ index ]
2015-08-05 18:42:35 +00:00
2018-09-05 20:52:32 +00:00
num_frames_in_video = self.GetNumFrames()
2017-06-21 21:15:59 +00:00
2018-09-05 20:52:32 +00:00
if index == num_frames_in_video - 1:
2017-06-21 21:15:59 +00:00
next_index = 0
else:
next_index = index + 1
self.GetReadyForFrame( next_index )
2015-08-05 18:42:35 +00:00
return frame
2018-09-05 20:52:32 +00:00
def GetHash( self ):
return self._media.GetHash()
2015-08-05 18:42:35 +00:00
2018-09-05 20:52:32 +00:00
def GetKey( self ):
return ( self._media.GetHash(), self._target_resolution )
2015-08-05 18:42:35 +00:00
2018-09-05 20:52:32 +00:00
def GetNumFrames( self ):
return self._media.GetNumFrames()
2015-08-05 18:42:35 +00:00
2016-07-27 21:53:34 +00:00
def GetReadyForFrame( self, next_index_to_expect ):
2015-08-05 18:42:35 +00:00
2018-09-05 20:52:32 +00:00
num_frames_in_video = self.GetNumFrames()
2015-08-05 18:42:35 +00:00
2018-12-05 22:35:30 +00:00
frame_request_is_impossible = FrameIndexOutOfRange( next_index_to_expect, 0, num_frames_in_video - 1 )
2017-06-21 21:15:59 +00:00
2018-09-05 20:52:32 +00:00
if frame_request_is_impossible:
2017-06-21 21:15:59 +00:00
return
2018-09-05 20:52:32 +00:00
with self._lock:
2016-07-27 21:53:34 +00:00
2018-09-05 20:52:32 +00:00
self._ideal_next_frame = next_index_to_expect
2015-08-05 18:42:35 +00:00
2018-09-05 20:52:32 +00:00
video_is_bigger_than_buffer = num_frames_in_video > self._num_frames_backwards + 1 + self._num_frames_forwards
2015-08-05 18:42:35 +00:00
2018-09-05 20:52:32 +00:00
if video_is_bigger_than_buffer:
2015-08-05 18:42:35 +00:00
2018-12-05 22:35:30 +00:00
current_ideal_is_out_of_buffer = self._buffer_start_index == -1 or FrameIndexOutOfRange( self._ideal_next_frame, self._buffer_start_index, self._buffer_end_index )
2015-08-05 18:42:35 +00:00
2018-09-05 20:52:32 +00:00
ideal_buffer_start_index = max( 0, self._ideal_next_frame - self._num_frames_backwards )
2015-08-05 18:42:35 +00:00
2018-09-05 20:52:32 +00:00
ideal_buffer_end_index = ( self._ideal_next_frame + self._num_frames_forwards ) % num_frames_in_video
2015-08-05 18:42:35 +00:00
2018-09-05 20:52:32 +00:00
if current_ideal_is_out_of_buffer:
# the current buffer won't get to where we want, so remake it
2015-08-05 18:42:35 +00:00
2016-07-27 21:53:34 +00:00
self._buffer_start_index = ideal_buffer_start_index
2018-09-05 20:52:32 +00:00
self._buffer_end_index = ideal_buffer_end_index
2015-08-05 18:42:35 +00:00
2018-09-05 20:52:32 +00:00
else:
2016-07-27 21:53:34 +00:00
2018-09-05 20:52:32 +00:00
# we can get to our desired position, but should we move the start and beginning on a bit?
2016-07-27 21:53:34 +00:00
2018-09-05 20:52:32 +00:00
# we do not ever want to shunt left (rewind)
# we do not want to shunt right if we don't have the earliest frames yet--be patient
# i.e. it is between the current start and the ideal
next_ideal_start_would_shunt_right = self._IndexInRange( ideal_buffer_start_index, self._buffer_start_index, self._ideal_next_frame )
have_next_ideal_start = self._HasFrame( ideal_buffer_start_index )
if next_ideal_start_would_shunt_right and have_next_ideal_start:
self._buffer_start_index = ideal_buffer_start_index
next_ideal_end_would_shunt_right = self._IndexInRange( ideal_buffer_end_index, self._buffer_end_index, self._buffer_start_index )
if next_ideal_end_would_shunt_right:
self._buffer_end_index = ideal_buffer_end_index
2015-08-05 18:42:35 +00:00
2018-09-05 20:52:32 +00:00
else:
2015-08-05 18:42:35 +00:00
self._buffer_start_index = 0
2018-09-05 20:52:32 +00:00
self._buffer_end_index = num_frames_in_video - 1
2015-08-05 18:42:35 +00:00
2018-09-05 20:52:32 +00:00
self._render_event.set()
2015-08-05 18:42:35 +00:00
2018-09-05 20:52:32 +00:00
def GetResolution( self ):
return self._media.GetResolution()
2016-07-27 21:53:34 +00:00
2018-09-05 20:52:32 +00:00
def GetSize( self ):
return self._target_resolution
2016-07-27 21:53:34 +00:00
2019-03-20 21:22:10 +00:00
def GetTimestampMS( self, frame_index ):
if self._media.GetMime() == HC.IMAGE_GIF:
return sum( self._durations[ : frame_index ] )
else:
return self._average_frame_duration * frame_index
2016-07-27 21:53:34 +00:00
def GetTotalDuration( self ):
2017-06-28 20:23:21 +00:00
if self._media.GetMime() == HC.IMAGE_GIF:
return sum( self._durations )
else:
return self._average_frame_duration * self.GetNumFrames()
2016-07-27 21:53:34 +00:00
def HasFrame( self, index ):
2018-09-05 20:52:32 +00:00
with self._lock:
2016-07-27 21:53:34 +00:00
2018-09-05 20:52:32 +00:00
return self._HasFrame( index )
2016-07-27 21:53:34 +00:00
2019-03-20 21:22:10 +00:00
def CanHaveVariableFramerate( self ):
with self._lock:
return self._media.GetMime() == HC.IMAGE_GIF
2016-10-19 20:02:56 +00:00
def IsInitialised( self ):
2018-09-05 20:52:32 +00:00
with self._lock:
return self._initialised
2016-10-19 20:02:56 +00:00
2018-09-05 20:52:32 +00:00
def IsScaled( self ):
return self._zoom != 1.0
2016-07-27 21:53:34 +00:00
def Stop( self ):
self._stop = True
2015-08-05 18:42:35 +00:00
class HydrusBitmap( object ):
2018-05-30 20:13:21 +00:00
def __init__( self, data, size, depth, compressed = True ):
2015-08-05 18:42:35 +00:00
2018-01-17 22:52:10 +00:00
if not LZ4_OK:
compressed = False
2015-08-05 18:42:35 +00:00
self._compressed = compressed
if self._compressed:
2017-06-14 21:19:11 +00:00
self._data = lz4.block.compress( data )
2015-08-05 18:42:35 +00:00
else:
self._data = data
self._size = size
2018-05-30 20:13:21 +00:00
self._depth = depth
2015-08-05 18:42:35 +00:00
def _GetData( self ):
if self._compressed:
2017-06-14 21:19:11 +00:00
return lz4.block.decompress( self._data )
2015-08-05 18:42:35 +00:00
else:
return self._data
2018-05-30 20:13:21 +00:00
def _GetWXBitmapFormat( self ):
if self._depth == 3:
return wx.BitmapBufferFormat_RGB
elif self._depth == 4:
return wx.BitmapBufferFormat_RGBA
2016-08-03 22:15:54 +00:00
def CopyToWxBitmap( self, wx_bmp ):
2018-05-30 20:13:21 +00:00
fmt = self._GetWXBitmapFormat()
wx_bmp.CopyFromBuffer( self._GetData(), fmt )
2016-08-03 22:15:54 +00:00
def GetDepth( self ):
2018-05-30 20:13:21 +00:00
return self._depth
2016-08-03 22:15:54 +00:00
2015-08-05 18:42:35 +00:00
def GetWxBitmap( self ):
( width, height ) = self._size
2018-05-30 20:13:21 +00:00
if self._depth == 3:
2017-11-29 21:48:23 +00:00
2018-01-03 22:37:30 +00:00
return wx.Bitmap.FromBuffer( width, height, self._GetData() )
2017-11-29 21:48:23 +00:00
2018-05-30 20:13:21 +00:00
elif self._depth == 4:
2017-11-29 21:48:23 +00:00
2018-01-03 22:37:30 +00:00
return wx.Bitmap.FromBufferRGBA( width, height, self._GetData() )
2017-11-29 21:48:23 +00:00
2015-08-05 18:42:35 +00:00
def GetWxImage( self ):
( width, height ) = self._size
2018-05-30 20:13:21 +00:00
if self._depth == 3:
2016-04-14 01:54:29 +00:00
return wx.ImageFromBuffer( width, height, self._GetData() )
2018-05-30 20:13:21 +00:00
elif self._depth == 4:
2015-08-05 18:42:35 +00:00
2018-01-03 22:37:30 +00:00
bitmap = wx.Bitmap.FromBufferRGBA( width, height, self._GetData() )
2015-08-05 18:42:35 +00:00
2018-04-11 22:30:40 +00:00
image = bitmap.ConvertToImage()
2015-08-05 18:42:35 +00:00
2016-08-24 18:36:56 +00:00
bitmap.Destroy()
2015-08-05 18:42:35 +00:00
return image
2016-04-14 01:54:29 +00:00
def GetEstimatedMemoryFootprint( self ):
return len( self._data )
2015-08-05 18:42:35 +00:00
2017-11-29 21:48:23 +00:00
def GetSize( self ):
return self._size
2017-03-15 20:13:04 +00:00