<s> import ClientFiles <EOL> import ClientImageHandling <EOL> import ClientVideoHandling <EOL> import HydrusConstants as HC <EOL> import HydrusData <EOL> import HydrusExceptions <EOL> import HydrusImageHandling <EOL> import HydrusGlobals <EOL> import HydrusThreading <EOL> import HydrusVideoHandling <EOL> import lz4 <EOL> import subprocess <EOL> import threading <EOL> import time <EOL> import wx <EOL> def GenerateHydrusBitmap ( path , compressed = True ) : <EOL> new_options = HydrusGlobals . client_controller . GetNewOptions ( ) <EOL> if new_options . GetBoolean ( '<STR_LIT>' ) : <EOL> pil_image = HydrusImageHandling . GeneratePILImage ( path ) <EOL> return GenerateHydrusBitmapFromPILImage ( pil_image , compressed = compressed ) <EOL> else : <EOL> numpy_image = None <EOL> try : <EOL> numpy_image = ClientImageHandling . GenerateNumpyImage ( path ) <EOL> return GenerateHydrusBitmapFromNumPyImage ( numpy_image , compressed = compressed ) <EOL> except : <EOL> if numpy_image is not None : <EOL> del numpy_image <EOL> pil_image = HydrusImageHandling . GeneratePILImage ( path ) <EOL> return GenerateHydrusBitmapFromPILImage ( pil_image , compressed = compressed ) <EOL> def GenerateHydrusBitmapFromNumPyImage ( numpy_image , compressed = True ) : <EOL> ( y , x , depth ) = numpy_image . shape <EOL> if depth == <NUM_LIT:4> : buffer_format = wx . BitmapBufferFormat_RGBA <EOL> else : buffer_format = wx . BitmapBufferFormat_RGB <EOL> return HydrusBitmap ( numpy_image . data , buffer_format , ( x , y ) , compressed = compressed ) <EOL> def GenerateHydrusBitmapFromPILImage ( pil_image , compressed = True ) : <EOL> if pil_image . mode == '<STR_LIT>' or ( pil_image . mode == '<STR_LIT:P>' and pil_image . info . has_key ( '<STR_LIT>' ) ) : <EOL> if pil_image . mode == '<STR_LIT:P>' : pil_image = pil_image . convert ( '<STR_LIT>' ) <EOL> format = wx . BitmapBufferFormat_RGBA <EOL> else : <EOL> if pil_image . mode != '<STR_LIT>' : pil_image = pil_image . convert ( '<STR_LIT>' ) <EOL> format = wx . BitmapBufferFormat_RGB <EOL> return HydrusBitmap ( pil_image . tobytes ( ) , format , pil_image . size , compressed = compressed ) <EOL> class RasterContainer ( object ) : <EOL> def __init__ ( self , media , target_resolution = None ) : <EOL> if target_resolution is None : target_resolution = media . GetResolution ( ) <EOL> ( width , height ) = target_resolution <EOL> if width == <NUM_LIT:0> or height == <NUM_LIT:0> : <EOL> target_resolution = ( <NUM_LIT:100> , <NUM_LIT:100> ) <EOL> self . _media = media <EOL> ( media_width , media_height ) = self . _media . GetResolution ( ) <EOL> ( target_width , target_height ) = target_resolution <EOL> if target_width > media_width or target_height > media_height : <EOL> target_resolution = self . _media . GetResolution ( ) <EOL> self . _target_resolution = target_resolution <EOL> ( target_width , target_height ) = target_resolution <EOL> hash = self . _media . GetHash ( ) <EOL> mime = self . _media . GetMime ( ) <EOL> client_files_manager = HydrusGlobals . client_controller . GetClientFilesManager ( ) <EOL> self . _path = client_files_manager . GetFilePath ( hash , mime ) <EOL> width_zoom = target_width / float ( media_width ) <EOL> height_zoom = target_height / float ( media_height ) <EOL> self . _zoom = min ( ( width_zoom , height_zoom ) ) <EOL> if self . _zoom > <NUM_LIT:1.0> : self . _zoom = <NUM_LIT:1.0> <EOL> class RasterContainerImage ( RasterContainer ) : <EOL> def __init__ ( self , media , target_resolution = None ) : <EOL> RasterContainer . __init__ ( self , media , target_resolution ) <EOL> self . _hydrus_bitmap = None <EOL> HydrusGlobals . client_controller . CallToThread ( self . _InitialiseHydrusBitmap ) <EOL> def _InitialiseHydrusBitmap ( self ) : <EOL> time . sleep ( <NUM_LIT> ) <EOL> new_options = HydrusGlobals . client_controller . GetNewOptions ( ) <EOL> if new_options . GetBoolean ( '<STR_LIT>' ) : <EOL> pil_image = HydrusImageHandling . GeneratePILImage ( self . _path ) <EOL> resized_pil_image = HydrusImageHandling . EfficientlyResizePILImage ( pil_image , self . _target_resolution ) <EOL> hydrus_bitmap = GenerateHydrusBitmapFromPILImage ( resized_pil_image ) <EOL> else : <EOL> try : <EOL> numpy_image = ClientImageHandling . GenerateNumpyImage ( self . _path ) <EOL> resized_numpy_image = ClientImageHandling . EfficientlyResizeNumpyImage ( numpy_image , self . _target_resolution ) <EOL> hydrus_bitmap = GenerateHydrusBitmapFromNumPyImage ( resized_numpy_image ) <EOL> except : <EOL> pil_image = HydrusImageHandling . GeneratePILImage ( self . _path ) <EOL> resized_pil_image = HydrusImageHandling . EfficientlyResizePILImage ( pil_image , self . _target_resolution ) <EOL> hydrus_bitmap = GenerateHydrusBitmapFromPILImage ( resized_pil_image ) <EOL> self . _hydrus_bitmap = hydrus_bitmap <EOL> def GetEstimatedMemoryFootprint ( self ) : <EOL> if self . _hydrus_bitmap is None : <EOL> ( width , height ) = self . _target_resolution <EOL> return width * height * <NUM_LIT:3> <EOL> else : <EOL> return self . _hydrus_bitmap . GetEstimatedMemoryFootprint ( ) <EOL> def GetHash ( self ) : return self . _media . GetHash ( ) <EOL> def GetHydrusBitmap ( self ) : return self . _hydrus_bitmap <EOL> def GetNumFrames ( self ) : return self . _media . GetNumFrames ( ) <EOL> def GetResolution ( self ) : return self . _media . GetResolution ( ) <EOL> def GetSize ( self ) : return self . _target_resolution <EOL> def GetZoom ( self ) : return self . _zoom <EOL> def IsRendered ( self ) : return self . _hydrus_bitmap is not None <EOL> def IsScaled ( self ) : return self . _zoom != <NUM_LIT:1.0> <EOL> class RasterContainerVideo ( RasterContainer ) : <EOL> BUFFER_SIZE = <NUM_LIT> * <NUM_LIT> * <NUM_LIT> <EOL> def __init__ ( self , media , target_resolution = None , init_position = <NUM_LIT:0> ) : <EOL> RasterContainer . __init__ ( self , media , target_resolution ) <EOL> self . _frames = { } <EOL> self . _last_index_asked_for = - <NUM_LIT:1> <EOL> self . _buffer_start_index = - <NUM_LIT:1> <EOL> self . _buffer_end_index = - <NUM_LIT:1> <EOL> ( x , y ) = self . _target_resolution <EOL> frame_buffer_length = self . BUFFER_SIZE / ( x * y * <NUM_LIT:3> ) <EOL> self . _num_frames_backwards = frame_buffer_length * <NUM_LIT:2> / <NUM_LIT:3> <EOL> self . _num_frames_forwards = frame_buffer_length / <NUM_LIT:3> <EOL> hash = self . _media . GetHash ( ) <EOL> mime = self . _media . GetMime ( ) <EOL> client_files_manager = HydrusGlobals . client_controller . GetClientFilesManager ( ) <EOL> path = client_files_manager . GetFilePath ( hash , mime ) <EOL> duration = self . _media . GetDuration ( ) <EOL> num_frames = self . _media . GetNumFrames ( ) <EOL> if self . _media . GetMime ( ) == HC . IMAGE_GIF : <EOL> self . _durations = HydrusImageHandling . GetGIFFrameDurations ( self . _path ) <EOL> self . _renderer = ClientVideoHandling . GIFRenderer ( path , num_frames , target_resolution ) <EOL> else : <EOL> self . _frame_duration = float ( duration ) / num_frames <EOL> self . _renderer = HydrusVideoHandling . VideoRendererFFMPEG ( path , mime , duration , num_frames , target_resolution ) <EOL> self . _render_lock = threading . Lock ( ) <EOL> self . _next_render_index = <NUM_LIT:0> <EOL> self . _render_to_index = - <NUM_LIT:1> <EOL> self . _rendered_first_frame = False <EOL> self . SetFramePosition ( init_position ) <EOL> def _MaintainBuffer ( self ) : <EOL> deletees = [ ] <EOL> for index in self . _frames . keys ( ) : <EOL> if self . _buffer_start_index < self . _buffer_end_index : <EOL> if index < self . _buffer_start_index or self . _buffer_end_index < index : deletees . append ( index ) <EOL> else : <EOL> if self . _buffer_end_index < index and index < self . _buffer_start_index : deletees . append ( index ) <EOL> for i in deletees : del self . _frames [ i ] <EOL> def _RENDERERSetRenderToPosition ( self , index ) : <EOL> with self . _render_lock : <EOL> if self . _render_to_index != index : <EOL> self . _render_to_index = index <EOL> HydrusGlobals . client_controller . CallToThread ( self . THREADRender ) <EOL> def _RENDERERSetFramePosition ( self , index ) : <EOL> with self . _render_lock : <EOL> if index == self . _next_render_index : return <EOL> else : <EOL> self . _renderer . set_position ( index ) <EOL> self . _next_render_index = index <EOL> self . _render_to_index = index <EOL> def THREADRender ( self ) : <EOL> num_frames = self . _media . GetNumFrames ( ) <EOL> while True : <EOL> time . sleep ( <NUM_LIT> ) <EOL> with self . _render_lock : <EOL> if not self . _rendered_first_frame or self . _next_render_index != ( self . _render_to_index + <NUM_LIT:1> ) % num_frames : <EOL> self . _rendered_first_frame = True <EOL> frame_index = self . _next_render_index <EOL> try : numpy_image = self . _renderer . read_frame ( ) <EOL> except Exception as e : <EOL> HydrusData . ShowException ( e ) <EOL> break <EOL> finally : self . _next_render_index = ( self . _next_render_index + <NUM_LIT:1> ) % num_frames <EOL> frame = GenerateHydrusBitmapFromNumPyImage ( numpy_image , compressed = False ) <EOL> wx . wx . CallAfter ( self . AddFrame , frame_index , frame ) <EOL> else : break <EOL> def AddFrame ( self , index , frame ) : self . _frames [ index ] = frame <EOL> def GetDuration ( self , index ) : <EOL> if self . _media . GetMime ( ) == HC . IMAGE_GIF : return self . _durations [ index ] <EOL> else : return self . _frame_duration <EOL> def GetFrame ( self , index ) : <EOL> frame = self . _frames [ index ] <EOL> self . _last_index_asked_for = index <EOL> self . _MaintainBuffer ( ) <EOL> return frame <EOL> def GetHash ( self ) : return self . _media . GetHash ( ) <EOL> def GetKey ( self ) : return ( self . _media . GetHash ( ) , self . _target_resolution ) <EOL> def GetNumFrames ( self ) : return self . _media . GetNumFrames ( ) <EOL> def GetResolution ( self ) : return self . _media . GetResolution ( ) <EOL> def GetSize ( self ) : return self . _target_resolution <EOL> def GetTotalDuration ( self ) : <EOL> if self . _media . GetMime ( ) == HC . IMAGE_GIF : return sum ( self . _durations ) <EOL> else : return self . _frame_duration * self . GetNumFrames ( ) <EOL> def GetZoom ( self ) : return self . _zoom <EOL> def HasFrame ( self , index ) : return index in self . _frames <EOL> def IsScaled ( self ) : return self . _zoom != <NUM_LIT:1.0> <EOL> def SetFramePosition ( self , index ) : <EOL> num_frames = self . GetNumFrames ( ) <EOL> if num_frames > self . _num_frames_backwards + <NUM_LIT:1> + self . _num_frames_forwards : <EOL> new_buffer_start_index = max ( <NUM_LIT:0> , index - self . _num_frames_backwards ) % num_frames <EOL> new_buffer_end_index = ( index + self . _num_frames_forwards ) % num_frames <EOL> if index == self . _last_index_asked_for : return <EOL> elif index < self . _last_index_asked_for : <EOL> if index < self . _buffer_start_index : <EOL> self . _buffer_start_index = new_buffer_start_index <EOL> self . _RENDERERSetFramePosition ( self . _buffer_start_index ) <EOL> self . _buffer_end_index = new_buffer_end_index <EOL> self . _RENDERERSetRenderToPosition ( self . _buffer_end_index ) <EOL> else : <EOL> currently_no_wraparound = self . _buffer_start_index < self . _buffer_end_index <EOL> self . _buffer_start_index = new_buffer_start_index <EOL> if currently_no_wraparound : <EOL> if index > self . _buffer_end_index : <EOL> self . _RENDERERSetFramePosition ( self . _buffer_start_index ) <EOL> self . _buffer_end_index = new_buffer_end_index <EOL> self . _RENDERERSetRenderToPosition ( self . _buffer_end_index ) <EOL> else : <EOL> if self . _buffer_end_index == - <NUM_LIT:1> : <EOL> self . _buffer_start_index = <NUM_LIT:0> <EOL> self . _RENDERERSetFramePosition ( <NUM_LIT:0> ) <EOL> self . _buffer_end_index = num_frames - <NUM_LIT:1> <EOL> self . _RENDERERSetRenderToPosition ( self . _buffer_end_index ) <EOL> self . _MaintainBuffer ( ) <EOL> class HydrusBitmap ( object ) : <EOL> def __init__ ( self , data , format , size , compressed = True ) : <EOL> self . _compressed = compressed <EOL> if self . _compressed : <EOL> self . _data = lz4 . dumps ( data ) <EOL> else : <EOL> self . _data = data <EOL> self . _format = format <EOL> self . _size = size <EOL> def _GetData ( self ) : <EOL> if self . _compressed : <EOL> return lz4 . loads ( self . _data ) <EOL> else : <EOL> return self . _data <EOL> def GetWxBitmap ( self ) : <EOL> ( width , height ) = self . _size <EOL> if self . _format == wx . BitmapBufferFormat_RGB : return wx . BitmapFromBuffer ( width , height , self . _GetData ( ) ) <EOL> else : return wx . BitmapFromBufferRGBA ( width , height , self . _GetData ( ) ) <EOL> def GetWxImage ( self ) : <EOL> ( width , height ) = self . _size <EOL> if self . _format == wx . BitmapBufferFormat_RGB : <EOL> return wx . ImageFromBuffer ( width , height , self . _GetData ( ) ) <EOL> else : <EOL> bitmap = wx . BitmapFromBufferRGBA ( width , height , self . _GetData ( ) ) <EOL> image = wx . ImageFromBitmap ( bitmap ) <EOL> wx . CallAfter ( bitmap . Destroy ) <EOL> return image <EOL> def GetEstimatedMemoryFootprint ( self ) : <EOL> return len ( self . _data ) <EOL> def GetSize ( self ) : return self . _size </s>
