コード例 #1
0
ファイル: ClientCaches.py プロジェクト: HOZHENWAI/hydrus
 def Clear( self ):
     
     with self._lock:
         
         self._data_cache.Clear()
         
         self._special_thumbs = {}
         
         names = [ 'hydrus', 'pdf', 'psd', 'audio', 'video', 'zip' ]
         
         bounding_dimensions = self._controller.options[ 'thumbnail_dimensions' ]
         
         for name in names:
             
             path = os.path.join( HC.STATIC_DIR, name + '.png' )
             
             numpy_image = ClientImageHandling.GenerateNumPyImage( path, HC.IMAGE_PNG )
             
             numpy_image_resolution = HydrusImageHandling.GetResolutionNumPy( numpy_image )
             
             target_resolution = HydrusImageHandling.GetThumbnailResolution( numpy_image_resolution, bounding_dimensions )
             
             numpy_image = HydrusImageHandling.ResizeNumPyImage( numpy_image, target_resolution )
             
             hydrus_bitmap = ClientRendering.GenerateHydrusBitmapFromNumPyImage( numpy_image )
             
             self._special_thumbs[ name ] = hydrus_bitmap
             
         
         self._controller.pub( 'notify_complete_thumbnail_reset' )
         
         self._waterfall_queue_quick = set()
         self._delayed_regeneration_queue_quick = set()
         
         self._RecalcQueues()
コード例 #2
0
 def _GetCurrentFrame( self ):
     
     if self._cv_mode:
         
         ( retval, numpy_image ) = self._cv_video.read()
         
         if not retval:
             
             self._next_render_index = ( self._next_render_index + 1 ) % self._num_frames
             
             raise HydrusExceptions.CantRenderWithCVException( 'CV could not render frame ' + str( self._next_render_index - 1 ) + '.' )
             
         
     else:
         
         current_frame = HydrusImageHandling.Dequantize( self._pil_image )
         
         if current_frame.mode == 'RGBA':
             
             if self._pil_canvas is None:
                 
                 self._pil_canvas = current_frame
                 
             else:
                 
                 self._pil_canvas.paste( current_frame, None, current_frame ) # use the rgba image as its own mask
                 
             
         elif current_frame.mode == 'RGB':
             
             self._pil_canvas = current_frame
             
         
         numpy_image = HydrusImageHandling.GenerateNumPyImageFromPILImage( self._pil_canvas )
         
     
     self._next_render_index = ( self._next_render_index + 1 ) % self._num_frames
     
     if self._next_render_index == 0:
         
         self._RewindGIF()
         
     else:
         
         if not self._cv_mode:
             
             self._pil_image.seek( self._next_render_index )
             
             if self._pil_global_palette is not None and self._pil_image.palette == self._pil_global_palette: # for some reason, when pil falls back from local palette to global palette, a bunch of important variables reset!
                 
                 self._pil_image.palette.dirty = self._pil_dirty
                 self._pil_image.palette.mode = self._pil_mode
                 self._pil_image.palette.rawmode = self._pil_rawmode
                 
             
         
     
     return numpy_image
コード例 #3
0
ファイル: HydrusFileHandling.py プロジェクト: ReAnzu/hydrus
def GenerateThumbnailBytes( path, target_resolution, mime, duration, num_frames, percentage_in = 35 ):
    
    if mime in ( HC.IMAGE_JPEG, HC.IMAGE_PNG, HC.IMAGE_GIF, HC.IMAGE_WEBP, HC.IMAGE_TIFF, HC.IMAGE_ICON ): # not apng atm
        
        thumbnail_bytes = HydrusImageHandling.GenerateThumbnailBytesFromStaticImagePath( path, target_resolution, mime )
        
    else:
        
        if mime == HC.APPLICATION_FLASH:
            
            ( os_file_handle, temp_path ) = HydrusPaths.GetTempPath()
            
            try:
                
                HydrusFlashHandling.RenderPageToFile( path, temp_path, 1 )
                
                thumbnail_bytes = HydrusImageHandling.GenerateThumbnailBytesFromStaticImagePath( temp_path, target_resolution, mime )
                
            except:
                
                thumb_path = os.path.join( HC.STATIC_DIR, 'flash.png' )
                
                thumbnail_bytes = HydrusImageHandling.GenerateThumbnailBytesFromStaticImagePath( thumb_path, target_resolution, mime )
                
            finally:
                
                HydrusPaths.CleanUpTempPath( os_file_handle, temp_path )
                
            
        else:
            
            renderer = HydrusVideoHandling.VideoRendererFFMPEG( path, mime, duration, num_frames, target_resolution )
            
            renderer.read_frame() # this initialises the renderer and loads the first frame as a fallback
            
            desired_thumb_frame = int( ( percentage_in / 100.0 ) * num_frames )
            
            renderer.set_position( desired_thumb_frame )
            
            numpy_image = renderer.read_frame()
            
            if numpy_image is None:
                
                raise Exception( 'Could not create a thumbnail from that video!' )
                
            
            numpy_image = HydrusImageHandling.ResizeNumPyImage( numpy_image, target_resolution ) # just in case ffmpeg doesn't deliver right
            
            thumbnail_bytes = HydrusImageHandling.GenerateThumbnailBytesNumPy( numpy_image, mime )
            
            renderer.Stop()
            
            del renderer
            
        
    
    return thumbnail_bytes
コード例 #4
0
    def GeneratePreImportHashAndStatus(self, status_hook=None):

        HydrusImageHandling.ConvertToPNGIfBMP(self._temp_path)

        if status_hook is not None:

            status_hook('calculating hash')

        hash = HydrusFileHandling.GetHashFromPath(self._temp_path)

        if HG.file_import_report_mode:

            HydrusData.ShowText('File import job hash: {}'.format(hash.hex()))

        if status_hook is not None:

            status_hook('checking for file status')

        self._pre_import_file_status = HG.client_controller.Read(
            'hash_status', 'sha256', hash, prefix='file recognised')

        # just in case
        self._pre_import_file_status.hash = hash

        self._pre_import_file_status = CheckFileImportStatus(
            self._pre_import_file_status)

        if HG.file_import_report_mode:

            HydrusData.ShowText('File import job pre-import status: {}'.format(
                self._pre_import_file_status.ToString()))
コード例 #5
0
 def _InitialisePIL( self ):
     
     if HG.media_load_report_mode:
         
         HydrusData.ShowText( 'Loading GIF with PIL' )
         
     
     self._cv_mode = False
     
     self._pil_image = HydrusImageHandling.GeneratePILImage( self._path )
     
     self._pil_canvas = None
     
     self._pil_global_palette = self._pil_image.palette
     
     if self._pil_global_palette is not None and False:
         
         self._pil_dirty = self._pil_image.palette.dirty
         self._pil_mode = self._pil_image.palette.mode
         self._pil_rawmode = self._pil_image.palette.rawmode
         
     
     self._next_render_index = 0
     self._last_frame = None
     
     # believe it or not, doing this actually fixed a couple of gifs!
     self._pil_image.seek( 1 )
     self._pil_image.seek( 0 )
コード例 #6
0
def GenerateNumPyImage(path, mime):

    force_pil = HG.client_controller.new_options.GetBoolean(
        'load_images_with_pil')

    return HydrusImageHandling.GenerateNumPyImage(path,
                                                  mime,
                                                  force_pil=force_pil)
コード例 #7
0
 def Clear( self ):
     
     with self._lock:
         
         self._data_cache.Clear()
         
         self._special_thumbs = {}
         
         names = [ 'hydrus', 'pdf', 'psd', 'clip', 'audio', 'video', 'zip' ]
         
         bounding_dimensions = self._controller.options[ 'thumbnail_dimensions' ]
         thumbnail_scale_type = self._controller.new_options.GetInteger( 'thumbnail_scale_type' )
         
         # it would be ideal to replace this with mimes_to_default_thumbnail_paths at a convenient point
         
         for name in names:
             
             path = os.path.join( HC.STATIC_DIR, '{}.png'.format( name ) )
             
             numpy_image = ClientImageHandling.GenerateNumPyImage( path, HC.IMAGE_PNG )
             
             numpy_image_resolution = HydrusImageHandling.GetResolutionNumPy( numpy_image )
             
             ( clip_rect, target_resolution ) = HydrusImageHandling.GetThumbnailResolutionAndClipRegion( numpy_image_resolution, bounding_dimensions, thumbnail_scale_type )
             
             if clip_rect is not None:
                 
                 numpy_image = HydrusImageHandling.ClipNumPyImage( numpy_image, clip_rect )
                 
             
             numpy_image = HydrusImageHandling.ResizeNumPyImage( numpy_image, target_resolution )
             
             hydrus_bitmap = ClientRendering.GenerateHydrusBitmapFromNumPyImage( numpy_image )
             
             self._special_thumbs[ name ] = hydrus_bitmap
             
         
         self._controller.pub( 'notify_complete_thumbnail_reset' )
         
         self._waterfall_queue_quick = set()
         self._delayed_regeneration_queue_quick = set()
         
         self._RecalcQueues()
コード例 #8
0
def LoadFromPNG( path ):
    
    # this is to deal with unicode paths, which cv2 can't handle
    ( os_file_handle, temp_path ) = HydrusTemp.GetTempPath()
    
    try:
        
        HydrusPaths.MirrorFile( path, temp_path )
        
        try:
            
            # unchanged because we want exact byte data, no conversions or other gubbins
            numpy_image = cv2.imread( temp_path, flags = IMREAD_UNCHANGED )
            
            if numpy_image is None:
                
                raise Exception()
                
            
        except Exception as e:
            
            try:
                
                # dequantize = False because we don't want to convert to RGB
                
                pil_image = HydrusImageHandling.GeneratePILImage( temp_path, dequantize = False )
                
                numpy_image = HydrusImageHandling.GenerateNumPyImageFromPILImage( pil_image )
                
            except Exception as e:
                
                HydrusData.ShowException( e )
                
                raise Exception( '"{}" did not appear to be a valid image!'.format( path ) )
                
            
        
    finally:
        
        HydrusTemp.CleanUpTempPath( os_file_handle, temp_path )
        
    
    return LoadFromNumPyImage( numpy_image )
コード例 #9
0
 def _RenderCurrentFrame( self ):
     
     if self._cv_mode:
         
         try:
             
             numpy_image = self._GetCurrentFrame()
             
             numpy_image = HydrusImageHandling.ResizeNumPyImage( numpy_image, self._target_resolution )
             
             numpy_image = cv2.cvtColor( numpy_image, cv2.COLOR_BGR2RGB )
             
         except HydrusExceptions.CantRenderWithCVException:
             
             if self._last_frame is None:
                 
                 if HG.media_load_report_mode:
                     
                     HydrusData.ShowText( 'OpenCV Failed to render a frame' )
                     
                 
                 self._InitialisePIL()
                 
                 numpy_image = self._RenderCurrentFrame()
                 
             else:
                 
                 numpy_image = self._last_frame
                 
             
         
     else:
         
         numpy_image = self._GetCurrentFrame()
         
         numpy_image = HydrusImageHandling.ResizeNumPyImage( numpy_image, self._target_resolution )
         
     
     self._last_frame = numpy_image
     
     return numpy_image
コード例 #10
0
def GenerateHydrusBitmapFromPILImage( pil_image, compressed = True ):
    
    pil_image = HydrusImageHandling.Dequantize( pil_image )
    
    if pil_image.mode == 'RGBA':
        
        depth = 4
        
    elif pil_image.mode == 'RGB':
        
        depth = 3
        
    
    return HydrusBitmap( pil_image.tobytes(), pil_image.size, depth, compressed = compressed )
コード例 #11
0
def ParseFileArguments(path, decompression_bombs_ok=False):

    HydrusImageHandling.ConvertToPNGIfBMP(path)

    hash = HydrusFileHandling.GetHashFromPath(path)

    try:

        mime = HydrusFileHandling.GetMime(path)

        if mime in HC.DECOMPRESSION_BOMB_IMAGES and not decompression_bombs_ok:

            if HydrusImageHandling.IsDecompressionBomb(path):

                raise HydrusExceptions.InsufficientCredentialsException(
                    'File seemed to be a Decompression Bomb, which you cannot upload!'
                )

        (size, mime, width, height, duration, num_frames, has_audio,
         num_words) = HydrusFileHandling.GetFileInfo(path, mime)

    except Exception as e:

        raise HydrusExceptions.BadRequestException('File ' + hash.hex() +
                                                   ' could not parse: ' +
                                                   str(e))

    args = ParsedRequestArguments()

    args['path'] = path
    args['hash'] = hash
    args['size'] = size
    args['mime'] = mime

    if width is not None: args['width'] = width
    if height is not None: args['height'] = height
    if duration is not None: args['duration'] = duration
    if num_frames is not None: args['num_frames'] = num_frames
    args['has_audio'] = has_audio
    if num_words is not None: args['num_words'] = num_words

    if mime in HC.MIMES_WITH_THUMBNAILS:

        try:

            bounding_dimensions = HC.SERVER_THUMBNAIL_DIMENSIONS

            target_resolution = HydrusImageHandling.GetThumbnailResolution(
                (width, height), bounding_dimensions)

            thumbnail_bytes = HydrusFileHandling.GenerateThumbnailBytes(
                path, target_resolution, mime, duration, num_frames)

        except Exception as e:

            tb = traceback.format_exc()

            raise HydrusExceptions.BadRequestException(
                'Could not generate thumbnail from that file:' + os.linesep +
                tb)

        args['thumbnail'] = thumbnail_bytes

    return args
コード例 #12
0
ファイル: ClientGUIMPV.py プロジェクト: HOZHENWAI/hydrus
 def SetMedia( self, media, start_paused = False ):
     
     if media == self._media:
         
         return
         
     
     self._media = media
     
     self._times_to_play_gif = 0
     
     if self._media is not None and self._media.GetMime() == HC.IMAGE_GIF and not HG.client_controller.new_options.GetBoolean( 'always_loop_gifs' ):
         
         hash = self._media.GetHash()
         
         path = HG.client_controller.client_files_manager.GetFilePath( hash, HC.IMAGE_GIF )
         
         self._times_to_play_gif = HydrusImageHandling.GetTimesToPlayGIF( path )
         
     
     self._current_seek_to_start_count = 0
     
     if self._media is None:
         
         self._player.pause = True
         
         if len( self._player.playlist ) > 0:
             
             try:
                 
                 self._player.command( 'playlist-remove', 'current' )
                 
             except:
                 
                 pass # sometimes happens after an error--screw it
                 
             
         
     else:
         
         hash = self._media.GetHash()
         mime = self._media.GetMime()
         
         client_files_manager = HG.client_controller.client_files_manager
         
         path = client_files_manager.GetFilePath( hash, mime )
         
         self._player.visibility = 'always'
         
         self._stop_for_slideshow = False
         
         self._player.pause = True
         
         try:
             
             self._player.loadfile( path )
             
         except Exception as e:
             
             HydrusData.ShowException( e )
             
         
         self._player.volume = self._GetCorrectCurrentVolume()
         self._player.mute = self._GetCorrectCurrentMute()
         self._player.pause = start_paused
コード例 #13
0
 def THREADRender( self ):
     
     hash = self._media.GetHash()
     mime = self._media.GetMime()
     duration = self._media.GetDuration()
     num_frames_in_video = self._media.GetNumFrames()
     
     client_files_manager = HG.client_controller.client_files_manager
     
     time.sleep( 0.00001 )
     
     if self._media.GetMime() == HC.IMAGE_GIF:
         
         ( self._durations, self._times_to_play_gif ) = HydrusImageHandling.GetGIFFrameDurations( self._path )
         
         self._renderer = ClientVideoHandling.GIFRenderer( self._path, num_frames_in_video, self._target_resolution )
         
     else:
         
         self._renderer = HydrusVideoHandling.VideoRendererFFMPEG( self._path, mime, duration, num_frames_in_video, self._target_resolution )
         
     
     # give ui a chance to draw a blank frame rather than hard-charge right into CPUland
     time.sleep( 0.00001 )
     
     self.GetReadyForFrame( self._init_position )
     
     with self._lock:
         
         self._initialised = True
         
     
     while True:
         
         if self._stop or HG.view_shutdown:
             
             self._renderer.Stop()
             
             self._renderer = None
             
             with self._lock:
                 
                 self._frames = {}
                 
             
             return
             
         
         #
         
         with self._lock:
             
             # lets see if we should move the renderer to a new position
             
             next_render_is_out_of_buffer = FrameIndexOutOfRange( self._next_render_index, self._buffer_start_index, self._buffer_end_index )
             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
             
         
         if need_to_render:
             
             with self._lock:
                 
                 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
                 
                 renderer = self._renderer
                 
             
             try:
                 
                 numpy_image = renderer.read_frame()
                 
             except Exception as e:
                 
                 HydrusData.ShowException( e )
                 
                 return
                 
             finally:
                 
                 with self._lock:
                     
                     self._last_index_rendered = frame_index
                     
                     self._next_render_index = ( self._next_render_index + 1 ) % num_frames_in_video
                     
                 
             
             with self._lock:
                 
                 if self._next_render_index == 0 and self._buffer_end_index != num_frames_in_video - 1:
                     
                     # we need to rewind renderer
                     
                     self._renderer.set_position( 0 )
                     
                     self._last_index_rendered = -1
                     
                 
                 should_save_frame = not self._HasFrame( frame_index )
                 
             
             if should_save_frame:
                 
                 frame = GenerateHydrusBitmapFromNumPyImage( numpy_image, compressed = False )
                 
                 with self._lock:
                     
                     self._frames[ frame_index ] = frame
                     
                     self._MaintainBuffer()
                     
                 
             
             with self._lock:
                 
                 work_still_to_do = self._last_index_rendered != self._buffer_end_index
                 
             
             if work_still_to_do:
                 
                 time.sleep( 0.0001 )
                 
             else:
                 
                 half_a_frame = ( self._average_frame_duration / 1000.0 ) * 0.5
                 
                 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
                 
             
         else:
             
             self._render_event.wait( 1 )
             
             self._render_event.clear()
コード例 #14
0
def GetFileInfo(path, mime=None, ok_to_look_for_hydrus_updates=False):

    size = os.path.getsize(path)

    if size == 0:

        raise HydrusExceptions.ZeroSizeFileException('File is of zero length!')

    if mime is None:

        mime = GetMime(
            path, ok_to_look_for_hydrus_updates=ok_to_look_for_hydrus_updates)

    if mime not in HC.ALLOWED_MIMES:

        if mime == HC.TEXT_HTML:

            raise HydrusExceptions.UnsupportedFileException(
                'Looks like HTML -- maybe the client needs to be taught how to parse this?'
            )

        elif mime == HC.APPLICATION_UNKNOWN:

            raise HydrusExceptions.UnsupportedFileException(
                'Unknown filetype!')

        else:

            raise HydrusExceptions.UnsupportedFileException(
                'Filetype is not permitted!')

    width = None
    height = None
    duration = None
    num_frames = None
    num_words = None

    if mime in HC.MIMES_THAT_DEFINITELY_HAVE_AUDIO:

        has_audio = True

    else:

        has_audio = False

    if mime in (HC.IMAGE_JPEG, HC.IMAGE_PNG, HC.IMAGE_GIF, HC.IMAGE_WEBP,
                HC.IMAGE_TIFF, HC.IMAGE_ICON):

        ((width, height), duration,
         num_frames) = HydrusImageHandling.GetImageProperties(path, mime)

    elif mime == HC.APPLICATION_CLIP:

        ((width, height), duration,
         num_frames) = HydrusClipHandling.GetClipProperties(path)

    elif mime == HC.APPLICATION_FLASH:

        ((width, height), duration,
         num_frames) = HydrusFlashHandling.GetFlashProperties(path)

    elif mime == HC.IMAGE_APNG:

        ((width, height), duration, num_frames,
         has_audio) = HydrusVideoHandling.GetFFMPEGAPNGProperties(path)

    elif mime == HC.APPLICATION_PDF:

        num_words = HydrusDocumentHandling.GetPDFNumWords(
            path)  # this now give None until a better solution can be found

    elif mime == HC.APPLICATION_PSD:

        (width, height) = HydrusImageHandling.GetPSDResolution(path)

    elif mime in HC.VIDEO:

        ((width, height), duration, num_frames,
         has_audio) = HydrusVideoHandling.GetFFMPEGVideoProperties(path)

    elif mime in HC.AUDIO:

        ffmpeg_lines = HydrusVideoHandling.GetFFMPEGInfoLines(path)

        (file_duration_in_s, stream_duration_in_s
         ) = HydrusVideoHandling.ParseFFMPEGDuration(ffmpeg_lines)

        duration = int(file_duration_in_s * 1000)

    if width is not None and width < 0:

        width *= -1

    if height is not None and height < 0:

        width *= -1

    if duration is not None and duration < 0:

        duration *= -1

    if num_frames is not None and num_frames < 0:

        num_frames *= -1

    if num_words is not None and num_words < 0:

        num_words *= -1

    return (size, mime, width, height, duration, num_frames, has_audio,
            num_words)
コード例 #15
0
    def GenerateInfo(self, status_hook=None):

        if self._pre_import_file_status.mime is None:

            if status_hook is not None:

                status_hook('generating filetype')

            mime = HydrusFileHandling.GetMime(self._temp_path)

            self._pre_import_file_status.mime = mime

        else:

            mime = self._pre_import_file_status.mime

        if HG.file_import_report_mode:

            HydrusData.ShowText('File import job mime: {}'.format(
                HC.mime_string_lookup[mime]))

        new_options = HG.client_controller.new_options

        if mime in HC.DECOMPRESSION_BOMB_IMAGES and not self._file_import_options.AllowsDecompressionBombs(
        ):

            if HG.file_import_report_mode:

                HydrusData.ShowText(
                    'File import job testing for decompression bomb')

            if HydrusImageHandling.IsDecompressionBomb(self._temp_path):

                if HG.file_import_report_mode:

                    HydrusData.ShowText(
                        'File import job: it was a decompression bomb')

                raise HydrusExceptions.DecompressionBombException(
                    'Image seems to be a Decompression Bomb!')

        if status_hook is not None:

            status_hook('generating file metadata')

        self._file_info = HydrusFileHandling.GetFileInfo(self._temp_path,
                                                         mime=mime)

        (size, mime, width, height, duration, num_frames, has_audio,
         num_words) = self._file_info

        if HG.file_import_report_mode:

            HydrusData.ShowText('File import job file info: {}'.format(
                self._file_info))

        if mime in HC.MIMES_WITH_THUMBNAILS:

            if status_hook is not None:

                status_hook('generating thumbnail')

            if HG.file_import_report_mode:

                HydrusData.ShowText('File import job generating thumbnail')

            bounding_dimensions = HG.client_controller.options[
                'thumbnail_dimensions']
            thumbnail_scale_type = HG.client_controller.new_options.GetInteger(
                'thumbnail_scale_type')

            (clip_rect, target_resolution
             ) = HydrusImageHandling.GetThumbnailResolutionAndClipRegion(
                 (width, height), bounding_dimensions, thumbnail_scale_type)

            percentage_in = HG.client_controller.new_options.GetInteger(
                'video_thumbnail_percentage_in')

            try:

                self._thumbnail_bytes = HydrusFileHandling.GenerateThumbnailBytes(
                    self._temp_path,
                    target_resolution,
                    mime,
                    duration,
                    num_frames,
                    clip_rect=clip_rect,
                    percentage_in=percentage_in)

            except Exception as e:

                raise HydrusExceptions.DamagedOrUnusualFileException(
                    'Could not render a thumbnail: {}'.format(str(e)))

        if mime in HC.FILES_THAT_HAVE_PERCEPTUAL_HASH:

            if status_hook is not None:

                status_hook('generating similar files metadata')

            if HG.file_import_report_mode:

                HydrusData.ShowText(
                    'File import job generating perceptual_hashes')

            self._perceptual_hashes = ClientImageHandling.GenerateShapePerceptualHashes(
                self._temp_path, mime)

            if HG.file_import_report_mode:

                HydrusData.ShowText(
                    'File import job generated {} perceptual_hashes: {}'.
                    format(len(self._perceptual_hashes), [
                        perceptual_hash.hex()
                        for perceptual_hash in self._perceptual_hashes
                    ]))

        if HG.file_import_report_mode:

            HydrusData.ShowText('File import job generating other hashes')

        if status_hook is not None:

            status_hook('generating additional hashes')

        self._extra_hashes = HydrusFileHandling.GetExtraHashesFromPath(
            self._temp_path)

        has_icc_profile = False

        if mime in HC.FILES_THAT_CAN_HAVE_ICC_PROFILE:

            try:

                pil_image = HydrusImageHandling.RawOpenPILImage(
                    self._temp_path)

                has_icc_profile = HydrusImageHandling.HasICCProfile(pil_image)

            except:

                pass

        self._has_icc_profile = has_icc_profile

        if mime in HC.FILES_THAT_CAN_HAVE_PIXEL_HASH and duration is None:

            try:

                self._pixel_hash = HydrusImageHandling.GetImagePixelHash(
                    self._temp_path, mime)

            except:

                pass

        self._file_modified_timestamp = HydrusFileHandling.GetFileModifiedTimestamp(
            self._temp_path)
コード例 #16
0
def GetFileInfo(path, mime=None, ok_to_look_for_hydrus_updates=False):

    size = os.path.getsize(path)

    if size == 0:

        raise HydrusExceptions.FileSizeException('File is of zero length!')

    if mime is None:

        mime = GetMime(
            path, ok_to_look_for_hydrus_updates=ok_to_look_for_hydrus_updates)

    if mime not in HC.ALLOWED_MIMES:

        if mime == HC.TEXT_HTML:

            raise HydrusExceptions.UnsupportedFileException(
                'Looks like HTML -- maybe the client needs to be taught how to parse this?'
            )

        elif mime == HC.APPLICATION_UNKNOWN:

            raise HydrusExceptions.UnsupportedFileException(
                'Unknown filetype!')

        else:

            raise HydrusExceptions.UnsupportedFileException(
                'Filetype is not permitted!')

    width = None
    height = None
    duration = None
    num_frames = None
    num_words = None

    if mime in (HC.IMAGE_JPEG, HC.IMAGE_PNG, HC.IMAGE_GIF, HC.IMAGE_WEBP,
                HC.IMAGE_TIFF, HC.IMAGE_ICON):
        ((width, height), duration,
         num_frames) = HydrusImageHandling.GetImageProperties(path, mime)
    elif mime == HC.APPLICATION_ZIP:
        temp_dir_path = HydrusPaths.GetTempDir()
        try:
            subprocess.call(["unzip", path, '-d', temp_dir_path])
            cover = sorted(list(Path(temp_dir_path).rglob("*.jpg")) +
                           list(Path(temp_dir_path).rglob("*.png")),
                           key=lambda p: p.name)[0].as_posix()
            ((width, height), duration,
             num_frames) = HydrusImageHandling.GetImageProperties(
                 cover, HC.IMAGE_PNG)
            # TODO: delete dir
        except Exception as e:
            (width, height, duration, num_frames) = (300, 300, 0, 0)
    elif mime == HC.APPLICATION_RAR:
        temp_dir_path = HydrusPaths.GetTempDir()
        try:
            subprocess.call(["unrar", path, temp_dir_path])
            cover = sorted(list(Path(temp_dir_path).rglob("*.jpg")) +
                           list(Path(temp_dir_path).rglob("*.png")),
                           key=lambda p: p.name)[0].as_posix()
            ((width, height), duration,
             num_frames) = HydrusImageHandling.GetImageProperties(
                 cover, HC.IMAGE_PNG)
        except Exception as e:
            (width, height, duration, num_frames) = (300, 300, 0, 0)

    elif mime == HC.APPLICATION_FLASH:

        ((width, height), duration,
         num_frames) = HydrusFlashHandling.GetFlashProperties(path)

    elif mime in (HC.IMAGE_APNG, HC.VIDEO_AVI, HC.VIDEO_FLV, HC.VIDEO_WMV,
                  HC.VIDEO_MOV, HC.VIDEO_MP4, HC.VIDEO_MKV, HC.VIDEO_REALMEDIA,
                  HC.VIDEO_WEBM, HC.VIDEO_MPEG):

        ((width, height), duration,
         num_frames) = HydrusVideoHandling.GetFFMPEGVideoProperties(path)

    elif mime == HC.APPLICATION_PDF:

        num_words = HydrusDocumentHandling.GetPDFNumWords(
            path)  # this now give None until a better solution can be found

    elif mime == HC.APPLICATION_PSD:

        (width, height) = HydrusImageHandling.GetPSDResolution(path)

    elif mime in HC.AUDIO:

        ffmpeg_lines = HydrusVideoHandling.GetFFMPEGInfoLines(path)

        (file_duration_in_s, stream_duration_in_s
         ) = HydrusVideoHandling.ParseFFMPEGDuration(ffmpeg_lines)

        duration = int(file_duration_in_s * 1000)

    if mime in HC.MIMES_THAT_DEFINITELY_HAVE_AUDIO:

        has_audio = True

    elif mime in HC.MIMES_THAT_MAY_HAVE_AUDIO:

        has_audio = HydrusAudioHandling.VideoHasAudio(path)

    else:

        has_audio = False

    if width is not None and width < 0:

        width *= -1

    if height is not None and height < 0:

        width *= -1

    if duration is not None and duration < 0:

        duration *= -1

    if num_frames is not None and num_frames < 0:

        num_frames *= -1

    if num_words is not None and num_words < 0:

        num_words *= -1

    return (size, mime, width, height, duration, num_frames, has_audio,
            num_words)
コード例 #17
0
def GenerateThumbnailBytes(path,
                           target_resolution,
                           mime,
                           duration,
                           num_frames,
                           percentage_in=35):

    if mime in (HC.IMAGE_JPEG, HC.IMAGE_PNG, HC.IMAGE_GIF, HC.IMAGE_WEBP,
                HC.IMAGE_TIFF, HC.IMAGE_ICON):  # not apng atm

        thumbnail_bytes = HydrusImageHandling.GenerateThumbnailBytesFromStaticImagePath(
            path, target_resolution, mime)
    elif mime in [HC.APPLICATION_ZIP]:
        temp_dir_path = HydrusPaths.GetTempDir()
        try:
            cmd = ["unzip", path, '-d', temp_dir_path]
            subprocess.call(cmd)
            cover = sorted(list(Path(temp_dir_path).rglob("*.jpg")) +
                           list(Path(temp_dir_path).rglob("*.png")),
                           key=lambda p: p.name)[0].as_posix()
            thumbnail_bytes = HydrusImageHandling.GenerateThumbnailBytesFromStaticImagePath(
                cover, target_resolution, mime)
        except Exception as e:
            thumb_path = os.path.join(HC.STATIC_DIR, 'zip.png')
            thumbnail_bytes = HydrusImageHandling.GenerateThumbnailBytesFromStaticImagePath(
                thumb_path, target_resolution, mime)
    elif mime in [HC.APPLICATION_RAR]:
        temp_dir_path = HydrusPaths.GetTempDir()
        try:
            cmd = ["unrar", 'x', path, temp_dir_path]
            subprocess.call(cmd)
            cover = sorted(list(Path(temp_dir_path).rglob("*.jpg")) +
                           list(Path(temp_dir_path).rglob("*.png")),
                           key=lambda p: p.name)[0].as_posix()
            thumbnail_bytes = HydrusImageHandling.GenerateThumbnailBytesFromStaticImagePath(
                cover, target_resolution, mime)
        except Exception as e:
            thumb_path = os.path.join(HC.STATIC_DIR, 'rar.png')
            thumbnail_bytes = HydrusImageHandling.GenerateThumbnailBytesFromStaticImagePath(
                thumb_path, target_resolution, mime)

    else:

        if mime == HC.APPLICATION_FLASH:

            (os_file_handle, temp_path) = HydrusPaths.GetTempPath()

            try:

                HydrusFlashHandling.RenderPageToFile(path, temp_path, 1)

                thumbnail_bytes = HydrusImageHandling.GenerateThumbnailBytesFromStaticImagePath(
                    temp_path, target_resolution, mime)

            except:

                thumb_path = os.path.join(HC.STATIC_DIR, 'flash.png')

                thumbnail_bytes = HydrusImageHandling.GenerateThumbnailBytesFromStaticImagePath(
                    thumb_path, target_resolution, mime)

            finally:

                HydrusPaths.CleanUpTempPath(os_file_handle, temp_path)

        else:

            renderer = HydrusVideoHandling.VideoRendererFFMPEG(
                path, mime, duration, num_frames, target_resolution)

            renderer.read_frame(
            )  # this initialises the renderer and loads the first frame as a fallback

            desired_thumb_frame = int((percentage_in / 100.0) * num_frames)

            renderer.set_position(desired_thumb_frame)

            numpy_image = renderer.read_frame()

            if numpy_image is None:

                raise Exception(
                    'Could not create a thumbnail from that video!')

            numpy_image = HydrusImageHandling.ResizeNumPyImage(
                numpy_image,
                target_resolution)  # just in case ffmpeg doesn't deliver right

            thumbnail_bytes = HydrusImageHandling.GenerateThumbnailBytesNumPy(
                numpy_image, mime)

            renderer.Stop()

            del renderer

    return thumbnail_bytes
コード例 #18
0
    def _GetThumbnailHydrusBitmap(self, display_media):

        bounding_dimensions = self._controller.options['thumbnail_dimensions']

        hash = display_media.GetHash()
        mime = display_media.GetMime()

        locations_manager = display_media.GetLocationsManager()

        try:

            path = self._controller.client_files_manager.GetThumbnailPath(
                display_media)

        except HydrusExceptions.FileMissingException as e:

            if locations_manager.IsLocal():

                summary = 'Unable to get thumbnail for file {}.'.format(
                    hash.hex())

                self._HandleThumbnailException(e, summary)

            return self._special_thumbs['hydrus']

        try:

            numpy_image = ClientImageHandling.GenerateNumPyImage(path, mime)

        except Exception as e:

            try:

                # file is malformed, let's force a regen
                self._controller.files_maintenance_manager.RunJobImmediately(
                    [display_media],
                    ClientFiles.REGENERATE_FILE_DATA_JOB_FORCE_THUMBNAIL,
                    pub_job_key=False)

            except Exception as e:

                summary = 'The thumbnail for file {} was not loadable. An attempt to regenerate it failed.'.format(
                    hash.hex())

                self._HandleThumbnailException(e, summary)

                return self._special_thumbs['hydrus']

            try:

                numpy_image = ClientImageHandling.GenerateNumPyImage(
                    path, mime)

            except Exception as e:

                summary = 'The thumbnail for file {} was not loadable. It was regenerated, but that file would not render either. Your image libraries or hard drive connection are unreliable. Please inform the hydrus developer what has happened.'.format(
                    hash.hex())

                self._HandleThumbnailException(e, summary)

                return self._special_thumbs['hydrus']

        (current_width,
         current_height) = HydrusImageHandling.GetResolutionNumPy(numpy_image)

        (media_width, media_height) = display_media.GetResolution()

        (expected_width,
         expected_height) = HydrusImageHandling.GetThumbnailResolution(
             (media_width, media_height), bounding_dimensions)

        exactly_as_expected = current_width == expected_width and current_height == expected_height

        rotation_exception = current_width == expected_height and current_height == expected_width

        correct_size = exactly_as_expected or rotation_exception

        if not correct_size:

            it_is_definitely_too_big = current_width >= expected_width and current_height >= expected_height

            if it_is_definitely_too_big:

                if HG.file_report_mode:

                    HydrusData.ShowText('Thumbnail {} too big.'.format(
                        hash.hex()))

                # the thumb we have is larger than desired. we can use it to generate what we actually want without losing significant data

                # this is _resize_, not _thumbnail_, because we already know the dimensions we want
                # and in some edge cases, doing getthumbresolution on existing thumb dimensions results in float/int conversion imprecision and you get 90px/91px regen cycles that never get fixed
                numpy_image = HydrusImageHandling.ResizeNumPyImage(
                    numpy_image, (expected_width, expected_height))

                if locations_manager.IsLocal():

                    # we have the master file, so it is safe to save our resized thumb back to disk since we can regen from source if needed

                    if HG.file_report_mode:

                        HydrusData.ShowText(
                            'Thumbnail {} too big, saving back to disk.'.
                            format(hash.hex()))

                    try:

                        try:

                            thumbnail_bytes = HydrusImageHandling.GenerateThumbnailBytesNumPy(
                                numpy_image, mime)

                        except HydrusExceptions.CantRenderWithCVException:

                            thumbnail_bytes = HydrusImageHandling.GenerateThumbnailBytesFromStaticImagePath(
                                path, (expected_width, expected_height), mime)

                    except:

                        summary = 'The thumbnail for file {} was too large, but an attempt to shrink it failed.'.format(
                            hash.hex())

                        self._HandleThumbnailException(e, summary)

                        return self._special_thumbs['hydrus']

                    try:

                        self._controller.client_files_manager.AddThumbnailFromBytes(
                            hash, thumbnail_bytes, silent=True)

                        self._controller.files_maintenance_manager.ClearJobs(
                            {hash}, ClientFiles.
                            REGENERATE_FILE_DATA_JOB_REFIT_THUMBNAIL)

                    except:

                        summary = 'The thumbnail for file {} was too large, but an attempt to save back the shrunk file failed.'.format(
                            hash.hex())

                        self._HandleThumbnailException(e, summary)

                        return self._special_thumbs['hydrus']

            else:

                # the thumb we have is either too small or completely messed up due to a previous ratio misparse

                media_is_same_size_as_current_thumb = current_width == media_width and current_height == media_height

                if media_is_same_size_as_current_thumb:

                    # the thumb is smaller than expected, but this is a 32x32 pixilart image or whatever, so no need to scale

                    if HG.file_report_mode:

                        HydrusData.ShowText(
                            'Thumbnail {} too small due to small source file.'.
                            format(hash.hex()))

                else:

                    numpy_image = HydrusImageHandling.ResizeNumPyImage(
                        numpy_image, (expected_width, expected_height))

                    if locations_manager.IsLocal():

                        # we have the master file, so we should regen the thumb from source

                        if HG.file_report_mode:

                            HydrusData.ShowText(
                                'Thumbnail {} too small, scheduling regeneration from source.'
                                .format(hash.hex()))

                        delayed_item = display_media.GetMediaResult()

                        with self._lock:

                            if delayed_item not in self._delayed_regeneration_queue_quick:

                                self._delayed_regeneration_queue_quick.add(
                                    delayed_item)

                                self._delayed_regeneration_queue.append(
                                    delayed_item)

                    else:

                        # we do not have the master file, so we have to scale up from what we have

                        if HG.file_report_mode:

                            HydrusData.ShowText(
                                'Thumbnail {} was too small, only scaling up due to no local source.'
                                .format(hash.hex()))

        hydrus_bitmap = ClientRendering.GenerateHydrusBitmapFromNumPyImage(
            numpy_image)

        return hydrus_bitmap
コード例 #19
0
def LoadFromPNG(path):

    # this is to deal with unicode paths, which cv2 can't handle
    (os_file_handle, temp_path) = HydrusTemp.GetTempPath()

    try:

        HydrusPaths.MirrorFile(path, temp_path)

        try:

            # unchanged because we want exact byte data, no conversions or other gubbins
            numpy_image = cv2.imread(temp_path, flags=IMREAD_UNCHANGED)

            if numpy_image is None:

                raise Exception()

        except Exception as e:

            try:

                # dequantize = False because we don't want to convert to RGB

                pil_image = HydrusImageHandling.GeneratePILImage(
                    temp_path, dequantize=False)

                numpy_image = HydrusImageHandling.GenerateNumPyImageFromPILImage(
                    pil_image)

            except Exception as e:

                HydrusData.ShowException(e)

                raise Exception('That did not appear to be a valid image!')

    finally:

        HydrusTemp.CleanUpTempPath(os_file_handle, temp_path)

    try:

        height = numpy_image.shape[0]
        width = numpy_image.shape[1]

        if len(numpy_image.shape) > 2:

            depth = numpy_image.shape[2]

            if depth != 1:

                raise Exception('The file did not appear to be monochrome!')

        try:

            complete_data = numpy_image.tostring()

            top_height_header = complete_data[:2]

            (top_height, ) = struct.unpack('!H', top_height_header)

            payload_and_header_bytes = complete_data[width * top_height:]

        except:

            raise Exception('Header bytes were invalid!')

        try:

            payload_length_header = payload_and_header_bytes[:4]

            (payload_bytes_length, ) = struct.unpack('!I',
                                                     payload_length_header)

            payload_bytes = payload_and_header_bytes[4:4 +
                                                     payload_bytes_length]

        except:

            raise Exception('Payload bytes were invalid!')

    except Exception as e:

        HydrusData.PrintException(e)

        message = 'The image loaded, but it did not seem to be a hydrus serialised png! The error was: {}'.format(
            str(e))
        message += os.linesep * 2
        message += 'If you believe this is a legit non-resized, non-converted hydrus serialised png, please send it to hydrus_dev.'

        raise Exception(message)

    return payload_bytes
コード例 #20
0
ファイル: ClientImageHandling.py プロジェクト: prof-m/hydrus
def GenerateShapePerceptualHashes( path, mime ):
    
    if HG.phash_generation_report_mode:
        
        HydrusData.ShowText( 'phash generation: loading image' )
        
    
    numpy_image = GenerateNumPyImage( path, mime )
    
    if HG.phash_generation_report_mode:
        
        HydrusData.ShowText( 'phash generation: image shape: {}'.format( numpy_image.shape ) )
        
    
    ( y, x, depth ) = numpy_image.shape
    
    if depth == 4:
        
        # doing this on 10000x10000 pngs eats ram like mad
        target_resolution = HydrusImageHandling.GetThumbnailResolution( ( x, y ), ( 1024, 1024 ) )
        
        numpy_image = HydrusImageHandling.ResizeNumPyImage( numpy_image, target_resolution )
        
        ( y, x, depth ) = numpy_image.shape
        
        # create weight and transform numpy_image to greyscale
        
        numpy_alpha = numpy_image[ :, :, 3 ]
        
        numpy_alpha_float = numpy_alpha / 255.0
        
        numpy_image_bgr = numpy_image[ :, :, :3 ]
        
        numpy_image_gray_bare = cv2.cvtColor( numpy_image_bgr, cv2.COLOR_RGB2GRAY )
        
        # create a white greyscale canvas
        
        white = numpy.ones( ( y, x ) ) * 255.0
        
        # paste the grayscale image onto the white canvas using: pixel * alpha + white * ( 1 - alpha )
        
        numpy_image_gray = numpy.uint8( ( numpy_image_gray_bare * numpy_alpha_float ) + ( white * ( numpy.ones( ( y, x ) ) - numpy_alpha_float ) ) )
        
    else:
        
        numpy_image_gray = cv2.cvtColor( numpy_image, cv2.COLOR_RGB2GRAY )
        
    
    if HG.phash_generation_report_mode:
        
        HydrusData.ShowText( 'phash generation: grey image shape: {}'.format( numpy_image_gray.shape ) )
        
    
    numpy_image_tiny = cv2.resize( numpy_image_gray, ( 32, 32 ), interpolation = cv2.INTER_AREA )
    
    if HG.phash_generation_report_mode:
        
        HydrusData.ShowText( 'phash generation: tiny image shape: {}'.format( numpy_image_tiny.shape ) )
        
    
    # convert to float and calc dct
    
    numpy_image_tiny_float = numpy.float32( numpy_image_tiny )
    
    if HG.phash_generation_report_mode:
        
        HydrusData.ShowText( 'phash generation: tiny float image shape: {}'.format( numpy_image_tiny_float.shape ) )
        HydrusData.ShowText( 'phash generation: generating dct' )
        
    
    dct = cv2.dct( numpy_image_tiny_float )
    
    # take top left 8x8 of dct
    
    dct_88 = dct[:8,:8]
    
    # get median of dct
    # exclude [0,0], which represents flat colour
    # this [0,0] exclusion is apparently important for mean, but maybe it ain't so important for median--w/e
    
    # old mean code
    # mask = numpy.ones( ( 8, 8 ) )
    # mask[0,0] = 0
    # average = numpy.average( dct_88, weights = mask )
    
    median = numpy.median( dct_88.reshape( 64 )[1:] )
    
    if HG.phash_generation_report_mode:
        
        HydrusData.ShowText( 'phash generation: median: {}'.format( median ) )
        
    
    # make a monochromatic, 64-bit hash of whether the entry is above or below the median
    
    dct_88_boolean = dct_88 > median
    
    if HG.phash_generation_report_mode:
        
        HydrusData.ShowText( 'phash generation: collapsing bytes' )
        
    
    # convert TTTFTFTF to 11101010 by repeatedly shifting answer and adding 0 or 1
    # you can even go ( a << 1 ) + b and leave out the initial param on the reduce call as bools act like ints for this
    # but let's not go crazy for another two nanoseconds
    def collapse_bools_to_binary_uint( a, b ):
        
        return ( a << 1 ) + int( b )
        
    
    list_of_bytes = []
    
    for i in range( 8 ):
        
        '''
        # old way of doing it, which compared value to median every time
        byte = 0
        
        for j in range( 8 ):
            
            byte <<= 1 # shift byte one left
            
            value = dct_88[i,j]
            
            if value > median:
                
                byte |= 1
                
            
        '''
        
        # this is a 0-255 int
        byte = reduce( collapse_bools_to_binary_uint, dct_88_boolean[i], 0 )
        
        list_of_bytes.append( byte )
        
    
    phash = bytes( list_of_bytes ) # this works!
    
    if HG.phash_generation_report_mode:
        
        HydrusData.ShowText( 'phash generation: phash: {}'.format( phash.hex() ) )
        
    
    # now discard the blank hash, which is 1000000... and not useful
    
    phashes = set()
    
    phashes.add( phash )
    
    phashes = DiscardBlankPerceptualHashes( phashes )
    
    if HG.phash_generation_report_mode:
        
        HydrusData.ShowText( 'phash generation: final phashes: {}'.format( len( phashes ) ) )
        
    
    # we good
    
    return phashes
コード例 #21
0
 def _GetThumbnailHydrusBitmap( self, display_media ):
     
     hash = display_media.GetHash()
     mime = display_media.GetMime()
     
     thumbnail_mime = HC.IMAGE_JPEG
     
     # we don't actually know this, it comes down to detailed stuff, but since this is png vs jpeg it isn't a huge deal down in the guts of image loading
     # only really matters with transparency, so anything that can be transparent we'll prime with a png thing
     # ain't like I am encoding EXIF rotation in my jpeg thumbs
     if mime in ( HC.IMAGE_APNG, HC.IMAGE_PNG, HC.IMAGE_GIF, HC.IMAGE_ICON, HC.IMAGE_WEBP ):
         
         thumbnail_mime = HC.IMAGE_PNG
         
     
     locations_manager = display_media.GetLocationsManager()
     
     try:
         
         path = self._controller.client_files_manager.GetThumbnailPath( display_media )
         
     except HydrusExceptions.FileMissingException as e:
         
         if locations_manager.IsLocal():
             
             summary = 'Unable to get thumbnail for file {}.'.format( hash.hex() )
             
             self._HandleThumbnailException( e, summary )
             
         
         return self._special_thumbs[ 'hydrus' ]
         
     
     try:
         
         numpy_image = ClientImageHandling.GenerateNumPyImage( path, thumbnail_mime )
         
     except Exception as e:
         
         try:
             
             # file is malformed, let's force a regen
             self._controller.files_maintenance_manager.RunJobImmediately( [ display_media ], ClientFiles.REGENERATE_FILE_DATA_JOB_FORCE_THUMBNAIL, pub_job_key = False )
             
         except Exception as e:
             
             summary = 'The thumbnail for file {} was not loadable. An attempt to regenerate it failed.'.format( hash.hex() )
             
             self._HandleThumbnailException( e, summary )
             
             return self._special_thumbs[ 'hydrus' ]
             
         
         try:
             
             numpy_image = ClientImageHandling.GenerateNumPyImage( path, thumbnail_mime )
             
         except Exception as e:
             
             summary = 'The thumbnail for file {} was not loadable. It was regenerated, but that file would not render either. Your image libraries or hard drive connection are unreliable. Please inform the hydrus developer what has happened.'.format( hash.hex() )
             
             self._HandleThumbnailException( e, summary )
             
             return self._special_thumbs[ 'hydrus' ]
             
         
     
     ( current_width, current_height ) = HydrusImageHandling.GetResolutionNumPy( numpy_image )
     
     ( media_width, media_height ) = display_media.GetResolution()
     
     bounding_dimensions = self._controller.options[ 'thumbnail_dimensions' ]
     
     thumbnail_scale_type = self._controller.new_options.GetInteger( 'thumbnail_scale_type' )
     
     ( clip_rect, ( expected_width, expected_height ) ) = HydrusImageHandling.GetThumbnailResolutionAndClipRegion( ( media_width, media_height ), bounding_dimensions, thumbnail_scale_type )
     
     exactly_as_expected = current_width == expected_width and current_height == expected_height
     
     rotation_exception = current_width == expected_height and current_height == expected_width
     
     correct_size = exactly_as_expected or rotation_exception
     
     if not correct_size:
         
         numpy_image = HydrusImageHandling.ResizeNumPyImage( numpy_image, ( expected_width, expected_height ) )
         
         if locations_manager.IsLocal():
             
             # we have the master file, so we should regen the thumb from source
             
             if HG.file_report_mode:
                 
                 HydrusData.ShowText( 'Thumbnail {} too small, scheduling regeneration from source.'.format( hash.hex() ) )
                 
             
             delayed_item = display_media.GetMediaResult()
             
             with self._lock:
                 
                 if delayed_item not in self._delayed_regeneration_queue_quick:
                     
                     self._delayed_regeneration_queue_quick.add( delayed_item )
                     
                     self._delayed_regeneration_queue.append( delayed_item )
                     
                 
             
         else:
             
             # we do not have the master file, so we have to scale up from what we have
             
             if HG.file_report_mode:
                 
                 HydrusData.ShowText( 'Stored thumbnail {} was the wrong size, only scaling due to no local source.'.format( hash.hex() ) )
                 
             
         
     
     hydrus_bitmap = ClientRendering.GenerateHydrusBitmapFromNumPyImage( numpy_image )
     
     return hydrus_bitmap