def test_phash( self ):
     
     phashes = ClientImageHandling.GenerateShapePerceptualHashes( os.path.join( HC.STATIC_DIR, 'hydrus.png' ), HC.IMAGE_PNG )
     
     self.assertEqual( phashes, set( [ b'\xb4M\xc7\xb2M\xcb8\x1c' ] ) )
     
     phashes = ClientImageHandling.DiscardBlankPerceptualHashes( { CC.BLANK_PHASH } )
     
     self.assertEqual( phashes, set() )
     
     phashes = ClientImageHandling.DiscardBlankPerceptualHashes( { b'\xb4M\xc7\xb2M\xcb8\x1c', CC.BLANK_PHASH } )
     
     self.assertEqual( phashes, set( [ b'\xb4M\xc7\xb2M\xcb8\x1c' ] ) )
Exemple #2
0
 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()
Exemple #3
0
    def _Initialise(self):

        # do this here so we are off the main thread and can wait
        client_files_manager = HG.client_controller.client_files_manager

        self._path = client_files_manager.GetFilePath(self._hash, self._mime)

        self._numpy_image = ClientImageHandling.GenerateNumPyImage(
            self._path, self._mime)

        if not self._this_is_for_metadata_alone:

            my_resolution_size = QC.QSize(self._resolution[0],
                                          self._resolution[1])
            my_numpy_size = QC.QSize(self._numpy_image.shape[1],
                                     self._numpy_image.shape[0])

            if my_resolution_size != my_numpy_size:

                HG.client_controller.Write(
                    'file_maintenance_add_jobs_hashes', {self._hash},
                    ClientFiles.REGENERATE_FILE_DATA_JOB_FILE_METADATA)

                m = 'There was a problem rendering the image with hash {}! Hydrus thinks its resolution is {}, but it was actually {}. Maybe hydrus missed rotation data when the file first imported?'.format(
                    self._hash.hex(), my_resolution_size, my_numpy_size)

                m += os.linesep * 2
                m += 'You may see some black squares in the image. A metadata regeneration has been scheduled, so with luck the image will fix itself soon.'

                HydrusData.ShowText(m)
Exemple #4
0
 def _Initialise( self ):
     
     # do this here so we are off the main thread and can wait
     client_files_manager = HG.client_controller.client_files_manager
     
     self._path = client_files_manager.GetFilePath( self._hash, self._mime )
     
     self._numpy_image = ClientImageHandling.GenerateNumPyImage( self._path, self._mime )
 def _GetNumPyImage( self, target_resolution = None ):
     
     if target_resolution is None:
         
         numpy_image = self._numpy_image
         
     else:
         
         numpy_image = ClientImageHandling.ResizeNumPyImageForMediaViewer( self._mime, self._numpy_image, ( target_resolution.width(), target_resolution.height() ) )
         
     
     return numpy_image
Exemple #6
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()
    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
def GenerateHydrusBitmap( path, mime, compressed = True ):
    
    numpy_image = ClientImageHandling.GenerateNumPyImage( path, mime )
    
    return GenerateHydrusBitmapFromNumPyImage( numpy_image, compressed = compressed )
 def _Initialise( self ):
     
     self._numpy_image = ClientImageHandling.GenerateNumPyImage( self._path, self._mime )
Exemple #10
0
    def _GetNumPyImage(self, clip_rect: QC.QRect, target_resolution: QC.QSize):

        if self._numpy_image is None:

            return numpy.zeros(
                (target_resolution.height(), target_resolution.width()),
                dtype='uint8')

        clip_size = clip_rect.size()
        clip_width = clip_size.width()
        clip_height = clip_size.height()

        (my_width, my_height) = self._resolution

        my_full_rect = QC.QRect(0, 0, my_width, my_height)

        ZERO_MARGIN = QC.QMargins(0, 0, 0, 0)

        clip_padding = ZERO_MARGIN
        target_padding = ZERO_MARGIN

        if clip_rect == my_full_rect:

            # full image

            source = self._numpy_image

        else:

            if target_resolution.width() > clip_width:

                # this is a tile that is being scaled up!
                # to reduce tiling artifacts (disagreement at otherwise good borders), we want to oversample the clip for our tile so lanczos and friends can get good neighbour data and then crop it
                # therefore, we'll figure out some padding for the clip, and then calculate what that means in the target end, and do a crop at the end

                # we want to pad. that means getting a larger resolution and keeping a record of the padding
                # can't pad if we are at 0 for x or y, or up against width/height max, but no problem in that case obviously

                # there is the float-int precision calculation problem again. we can't pick a padding of 3 in the clip if we are zooming by 150%--what do we clip off in the target: 4 or 5 pixels? whatever, we get warping
                # first let's figure a decent zoom estimate:

                zoom_estimate = target_resolution.width(
                ) / clip_width if target_resolution.width(
                ) > target_resolution.height(
                ) else target_resolution.height() / clip_height

                # now, if zoom is 150% (as a fraction, 3/2), we want a padding at the target of something that divides by 3 cleanly, or, since we are choosing at the clip in this case and will be multiplying, something that divides cleanly to 67%

                zoom_estimate_for_clip_padding_multiplier = 1 / zoom_estimate

                # and we want a nice padding size limit, big enough to make clean numbers but not so big that we are rendering the 8 tiles in a square around the one we want
                no_bigger_than = max(4, (clip_width + clip_height) // 4)

                nice_number = HydrusData.GetNicelyDivisibleNumberForZoom(
                    zoom_estimate_for_clip_padding_multiplier, no_bigger_than)

                if nice_number != -1:

                    # lanczos, I think, uses 4x4 neighbour grid to render. we'll say padding of 4 pixels to be safe for now, although 2 or 3 is probably correct???
                    # however it works, numbers these small are not a big deal

                    while nice_number < 4:

                        nice_number *= 2

                    PADDING_AMOUNT = nice_number

                    # LIMITATION: There is still a problem here for the bottom and rightmost edges. These tiles are not squares, so the shorter/thinner dimension my be an unpleasant number and be warped _anyway_, regardless of nice padding
                    # perhaps there is a way to boost left or top padding so we are rendering a full square tile but still cropping our target at the end, but with a little less warping
                    # I played around with this idea but did not have much success

                    LEFT_PADDING_AMOUNT = PADDING_AMOUNT
                    TOP_PADDING_AMOUNT = PADDING_AMOUNT

                    left_padding = min(LEFT_PADDING_AMOUNT, clip_rect.x())
                    top_padding = min(TOP_PADDING_AMOUNT, clip_rect.y())
                    right_padding = min(PADDING_AMOUNT, (my_width - 1) -
                                        clip_rect.bottomRight().x())
                    bottom_padding = min(PADDING_AMOUNT, (my_height - 1) -
                                         clip_rect.bottomRight().y())

                    clip_padding = QC.QMargins(left_padding, top_padding,
                                               right_padding, bottom_padding)

                    target_padding = clip_padding * zoom_estimate

            clip_rect_with_padding = clip_rect + clip_padding

            (x, y, clip_width, clip_height) = (clip_rect_with_padding.x(),
                                               clip_rect_with_padding.y(),
                                               clip_rect_with_padding.width(),
                                               clip_rect_with_padding.height())

            source = self._numpy_image[y:y + clip_height, x:x + clip_width]

        if target_resolution == clip_size:

            # 100% zoom

            result = source

        else:

            if clip_padding == ZERO_MARGIN:

                result = ClientImageHandling.ResizeNumPyImageForMediaViewer(
                    self._mime, source,
                    (target_resolution.width(), target_resolution.height()))

            else:

                target_width_with_padding = target_resolution.width(
                ) + target_padding.left() + target_padding.right()
                target_height_with_padding = target_resolution.height(
                ) + target_padding.top() + target_padding.bottom()

                result = ClientImageHandling.ResizeNumPyImageForMediaViewer(
                    self._mime, source,
                    (target_width_with_padding, target_height_with_padding))

                y = target_padding.top()
                x = target_padding.left()

                result = result[y:y + target_resolution.height(),
                                x:x + target_resolution.width()]

        if not result.data.c_contiguous:

            result = result.copy()

        return result
Exemple #11
0
    def _Initialise(self):

        # do this here so we are off the main thread and can wait
        client_files_manager = HG.client_controller.client_files_manager

        self._path = client_files_manager.GetFilePath(self._hash, self._mime)

        try:

            self._numpy_image = ClientImageHandling.GenerateNumPyImage(
                self._path, self._mime)

        except Exception as e:

            HydrusData.ShowText(
                'Problem rendering image at "{}"! Error follows:'.format(
                    self._path))

            HydrusData.ShowException(e)

        if not self._this_is_for_metadata_alone:

            if self._numpy_image is None:

                m = 'There was a problem rendering the image with hash {}! It may be damaged.'.format(
                    self._hash.hex())

                m += os.linesep * 2
                m += 'Jobs to check its integrity and metadata have been scheduled. If it is damaged, it may be redownloaded or removed from the client completely. If it is not damaged, it may be fixed automatically or further action may be required.'

                HydrusData.ShowText(m)

                HG.client_controller.Write(
                    'file_maintenance_add_jobs_hashes', {self._hash},
                    ClientFiles.
                    REGENERATE_FILE_DATA_JOB_FILE_INTEGRITY_DATA_TRY_URL_ELSE_REMOVE_RECORD
                )
                HG.client_controller.Write(
                    'file_maintenance_add_jobs_hashes', {self._hash},
                    ClientFiles.REGENERATE_FILE_DATA_JOB_FILE_METADATA)

            else:

                my_resolution_size = QC.QSize(self._resolution[0],
                                              self._resolution[1])
                my_numpy_size = QC.QSize(self._numpy_image.shape[1],
                                         self._numpy_image.shape[0])

                if my_resolution_size != my_numpy_size:

                    m = 'There was a problem rendering the image with hash {}! Hydrus thinks its resolution is {}, but it was actually {}.'.format(
                        self._hash.hex(), my_resolution_size, my_numpy_size)

                    m += os.linesep * 2
                    m += 'You may see some black squares in the image. A metadata regeneration has been scheduled, so with luck the image will fix itself soon.'

                    HydrusData.ShowText(m)

                    HG.client_controller.Write(
                        'file_maintenance_add_jobs_hashes', {self._hash},
                        ClientFiles.REGENERATE_FILE_DATA_JOB_FILE_METADATA)
Exemple #12
0
    def _GetNumPyImage(self, clip_rect: QC.QRect, target_resolution: QC.QSize):

        clip_size = clip_rect.size()

        (my_width, my_height) = self._resolution

        my_full_rect = QC.QRect(0, 0, my_width, my_height)

        ZERO_MARGIN = QC.QMargins(0, 0, 0, 0)

        clip_padding = ZERO_MARGIN
        target_padding = ZERO_MARGIN

        if clip_rect == my_full_rect:

            # full image

            source = self._numpy_image

        else:

            if target_resolution.width() > clip_size.width():

                # this is a tile that is being scaled!
                # to reduce tiling artifacts, we want to oversample the clip for our tile so lanczos and friends can get good neighbour data and then crop it
                # therefore, we'll figure out some padding for the clip, and then calculate what that means in the target end, and do a crop at the end

                # we want to pad. that means getting a larger resolution and keeping a record of the padding
                # can't pad if we are at 0 for x or y, or up against width/height max
                # but if we can pad, we will get a larger clip size and then _clip_ a better target endpoint. this is tricky.

                PADDING_AMOUNT = 4

                left_padding = min(PADDING_AMOUNT, clip_rect.x())
                top_padding = min(PADDING_AMOUNT, clip_rect.y())
                right_padding = min(PADDING_AMOUNT,
                                    my_width - clip_rect.bottomRight().x())
                bottom_padding = min(PADDING_AMOUNT,
                                     my_height - clip_rect.bottomRight().y())

                clip_padding = QC.QMargins(left_padding, top_padding,
                                           right_padding, bottom_padding)

                # this is ugly and super inaccurate
                target_padding = clip_padding * (target_resolution.width() /
                                                 clip_size.width())

            clip_rect_with_padding = clip_rect + clip_padding

            (x, y, clip_width, clip_height) = (clip_rect_with_padding.x(),
                                               clip_rect_with_padding.y(),
                                               clip_rect_with_padding.width(),
                                               clip_rect_with_padding.height())

            source = self._numpy_image[y:y + clip_height, x:x + clip_width]

        if target_resolution == clip_size:

            # 100% zoom

            result = source

        else:

            if clip_padding == ZERO_MARGIN:

                result = ClientImageHandling.ResizeNumPyImageForMediaViewer(
                    self._mime, source,
                    (target_resolution.width(), target_resolution.height()))

            else:

                target_width_with_padding = target_resolution.width(
                ) + target_padding.left() + target_padding.right()
                target_height_with_padding = target_resolution.height(
                ) + target_padding.top() + target_padding.bottom()

                result = ClientImageHandling.ResizeNumPyImageForMediaViewer(
                    self._mime, source,
                    (target_width_with_padding, target_height_with_padding))

                y = target_padding.top()
                x = target_padding.left()

                result = result[y:y + target_resolution.height(),
                                x:x + target_resolution.width()]

        if not result.data.c_contiguous:

            result = result.copy()

        return result
Exemple #13
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)
Exemple #14
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