def configure(cls, qscreen=None, colorSpace=-1, workingProfile=None): """ Try to configure color management for the monitor specified by QScreen, and build an image transformation from the working profile (default sRGB) to the monitor profile. This transformation is convenient to match image colors to screen colors. @param qscreen: QScreen instance @type qscreen: QScreen @param colorSpace: @type colorSpace @param workingProfile: @type workingProfile: """ cls.HAS_COLOR_MANAGE = False # look for valid profiles try: # get monitor profile as CmsProfile object. if qscreen is not None: cls.monitorProfile = cls.getMonitorProfile(qscreen=qscreen) if cls.monitorProfile is None: # not handled by PIL raise ValueError # get profile info, a PyCmsError exception is raised if monitorProfile is invalid cls.monitorProfileInfo = getProfileInfo(cls.monitorProfile) # get working profile as CmsProfile object if colorSpace == 1: cls.workingProfile = getOpenProfile(SRGB_PROFILE_PATH) elif colorSpace == 2: cls.workingProfile = getOpenProfile(ADOBE_RGB_PROFILE_PATH) elif type(workingProfile) is ImageCmsProfile: cls.workingProfile = workingProfile else: cls.workingProfile = getOpenProfile( SRGB_PROFILE_PATH) # default cls.workingProfileInfo = getProfileInfo(cls.workingProfile) # init CmsTransform object : working profile ---> monitor profile cls.workToMonTransform = buildTransformFromOpenProfiles( cls.workingProfile, cls.monitorProfile, "RGB", "RGB", renderingIntent=INTENT_PERCEPTUAL) """ INTENT_PERCEPTUAL = 0 (DEFAULT) (ImageCms.INTENT_PERCEPTUAL) INTENT_RELATIVE_COLORIMETRIC = 1 (ImageCms.INTENT_RELATIVE_COLORIMETRIC) INTENT_SATURATION = 2 (ImageCms.INTENT_SATURATION) INTENT_ABSOLUTE_COLORIMETRIC = 3 (ImageCms.INTENT_ABSOLUTE_COLORIMETRIC) """ cls.HAS_COLOR_MANAGE = (cls.monitorProfile is not None) and \ (cls.workingProfile is not None) and (cls.workToMonTransform is not None) cls.COLOR_MANAGE = cls.HAS_COLOR_MANAGE and cls.COLOR_MANAGE except (OSError, IOError) as e: print("I/O error({0}): {1}".format(e.errno, e.strerror)) except (ValueError, TypeError, PyCMSError): pass except: print("Unexpected error:", sys.exc_info()[0]) raise
def __generate_master__(self): """ create a master file from the original already in the package and set all metadata """ # open original # capture existing ICC profile (if there is one) # if no ICC profile, assign sRGB # if ICC profile and != sRGB, convert to sRGB # save as uncompressed TIFF logger = logging.getLogger(sys._getframe().f_code.co_name) profile_srgb2 = os.path.join( os.path.dirname(os.path.abspath(__file__)), 'icc', 'sRGB_IEC61966-2-1_black_scaled.icc') profile_srgb4 = os.path.join( os.path.dirname(os.path.abspath(__file__)), 'icc', 'sRGB_v4_ICC_preference.icc') original_path = os.path.join(self.path, self.original) original_image = Image.open(original_path) try: raw_profile = original_image.info['icc_profile'] except KeyError: raw_profile = getOpenProfile(profile_srgb2).tobytes() logger.warning( '{original} does not have an internal ICC color profile'. format(original=self.original)) else: logger.debug( 'detected internal ICC color profile in {original}'.format( original=self.original)) original_profile = getOpenProfile(BytesIO(raw_profile)) original_profile_name = getProfileName(original_profile).strip() target_profile = getOpenProfile(profile_srgb4) target_profile_name = getProfileName(target_profile).strip() logger.debug( 'attempting to convert from "{original}" to "{target}"'.format( original=original_profile_name, target=target_profile_name)) converted_image = profileToProfile(original_image, original_profile, target_profile) master_path = os.path.join(self.path, 'master.tif') tiffinfo = TiffImagePlugin.ImageFileDirectory() tiffinfo[TiffImagePlugin.ICCPROFILE] = target_profile.tobytes() tiffinfo.tagtype[ TiffImagePlugin.ICCPROFILE] = 1 # byte according to TiffTags.TYPES converted_image.DEBUG = True converted_image.save(master_path, tiffinfo=tiffinfo) hash_master = hash_of_file(master_path) logger.debug('saved converted master image to {master}'.format( master=master_path)) self.__append_event__( 'created master.tif file at {master}'.format(master=master_path)) self.manifest.set('master.tif', hash_master)
def test_master_maker_icc(self): srgb = 'IEC 61966-2-1 Default RGB Colour Space - sRGB' pp = 'ProPhoto - little cms' expected_icc = { 'cat_drawer.jpf': srgb, 'cat_drawer.jpg': srgb, 'cat_drawer.png': srgb, 'cat_drawer.tif': srgb, 'cat_drawer_adobe.tif': pp, 'cat_drawer_posterized.bmp': srgb, 'cat_drawer_posterized.gif': srgb, 'cat_drawer_posterized.png': srgb, 'cat_drawer_posterized.tif': srgb, 'morning-alley-2010.jpg': srgb } for fn, im in self.images.items(): self.logger.debug('icc test handling file {}'.format(fn)) maker = MasterMaker(im, logging_threshold=logging.DEBUG) maker.make() master = maker.master assert_equal( getProfileName( getOpenProfile( BytesIO(master.info['icc_profile']))).strip(), expected_icc[fn])
def B_get_display_profile(handle=None, device_id=None): """ bLUe version of ImageCms get_display_profile. @param handle: screen handle (Windows) @type handle: int @param device_id: name of display @type device_id: str @return: monitor profile or None @rtype: ImageCmsProfile or None """ profile_path = DEFAULT_MONITOR_PROFILE_PATH if sys.platform == "win32": profile_path = core.get_display_profile_win32(handle, 1) elif HAS_GI: try: from PySide2.QtWidgets import QApplication, QMainWindow GIO_CANCELLABLE = Gio.Cancellable.new() client = Colord.Client.new() client.connect_sync(GIO_CANCELLABLE) device = client.find_device_sync('xrandr-' + device_id, GIO_CANCELLABLE) device.connect_sync(GIO_CANCELLABLE) default_profile = device.get_default_profile() default_profile.connect_sync(GIO_CANCELLABLE) profile_path = default_profile.get_filename() except (NameError, ImportError, GLib.GError) as e: from bLUeTop.QtGui1 import window dlgWarn('Cannot detect monitor profile', info=str(e), parent=window) try: Cms_profile = getOpenProfile(profile_path) except PyCMSError: Cms_profile = get_default_monitor_profile() return Cms_profile
def test_master_maker_save(self): self.logger.debug('test_master_maker_save') profile_target_path = abspath(join( dirname(realpath(__file__)), '..', 'isaw', 'awib', 'icc', '{}.icc'.format('ProPhoto'))) profile_target = getOpenProfile(profile_target_path) i = 0 for fn, im_in in self.images.items(): i += 1 self.logger.debug('input filename: "{}"'.format(fn)) maker = MasterMaker(im_in, logging_threshold=logging.DEBUG) master = maker.make() name, extension = splitext(fn) fn_out = 'test{}.tif'.format(i) self.logger.debug('output filename: "{}"'.format(fn_out)) path_out = join(self.data_dir, 'scratch', fn_out) maker.save(path_out) continue im_out = Image.open(path_out) im_out.load() try: im_out.fp.close() except AttributeError: pass assert_equal(im_out.format, 'TIFF') assert_equal(master.mode, im_out.mode) stat_im_out = Stat(im_out) stat_master = Stat(master) assert_equal(stat_im_out.extrema, stat_master.extrema) assert_equal(stat_im_out.count, stat_master.count) assert_equal(stat_im_out.sum, stat_master.sum) assert_equal(stat_im_out.mean, stat_master.mean) assert_equal(stat_im_out.median, stat_master.median) assert_equal(stat_im_out.rms, stat_master.rms) assert_equal(stat_im_out.var, stat_master.var) self.logger.debug('info keys: {}'.format(im_out.info.keys())) assert_equal( getProfileName( getOpenProfile(BytesIO(master.info['icc_profile']))), getProfileName(profile_target))
def get_default_monitor_profile(): """ try to find a default image profile @return: profile or None @rtype: ImageCmsProfile or None """ profile = None try: profile = getOpenProfile(DEFAULT_MONITOR_PROFILE_PATH) except PyCMSError: pass return profile
def __generate_master__(self): """ create a master file from the original already in the package and set all metadata """ # open original # capture existing ICC profile (if there is one) # if no ICC profile, assign sRGB # if ICC profile and != sRGB, convert to sRGB # save as uncompressed TIFF logger = logging.getLogger(sys._getframe().f_code.co_name) profile_srgb2 = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'icc', 'sRGB_IEC61966-2-1_black_scaled.icc') profile_srgb4 = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'icc', 'sRGB_v4_ICC_preference.icc') original_path = os.path.join(self.path, self.original) original_image = Image.open(original_path) try: raw_profile = original_image.info['icc_profile'] except KeyError: raw_profile = getOpenProfile(profile_srgb2).tobytes() logger.warning('{original} does not have an internal ICC color profile'.format(original=self.original)) else: logger.debug('detected internal ICC color profile in {original}'.format(original=self.original)) original_profile = getOpenProfile(BytesIO(raw_profile)) original_profile_name = getProfileName(original_profile).strip() target_profile = getOpenProfile(profile_srgb4) target_profile_name = getProfileName(target_profile).strip() logger.debug('attempting to convert from "{original}" to "{target}"'.format(original=original_profile_name, target=target_profile_name)) converted_image = profileToProfile(original_image, original_profile, target_profile) master_path = os.path.join(self.path, 'master.tif') tiffinfo = TiffImagePlugin.ImageFileDirectory() tiffinfo[TiffImagePlugin.ICCPROFILE] = target_profile.tobytes() tiffinfo.tagtype[TiffImagePlugin.ICCPROFILE] = 1 # byte according to TiffTags.TYPES converted_image.DEBUG=True converted_image.save(master_path, tiffinfo=tiffinfo) hash_master = hash_of_file(master_path) logger.debug('saved converted master image to {master}'.format(master=master_path)) self.__append_event__('created master.tif file at {master}'.format(master=master_path)) self.manifest.set('master.tif', hash_master)
def get_default_working_profile(): """ try to find a default image profile @return: profile @rtype: ImageCmsProfile """ try: profile = getOpenProfile(SRGB_PROFILE_PATH) except PyCMSError: dlgWarn( 'No valid sRGB color profile found.\nSet SYSTEM_PROFILE_DIR and SRGB_PROFILE_NAME in your config.json', info='Invalid profile %s' % SRGB_PROFILE_PATH) sys.exit() return profile
def _get_original_profile(self): try: raw_profile = getOpenProfile( BytesIO(self.original.info['icc_profile'])) except KeyError: raw_profile = self._get_profile_from_file( 'sRGB_IEC61966-2-1_black_scaled') self.log( 'Original image does not have an internal ICC color profile.' '{} has been assigned.' ''.format(getProfileName(raw_profile).strip())) else: self.log( 'Detected internal ICC color profile in original image: {}.' ''.format(getProfileName(raw_profile).strip())) return raw_profile
def test_profiles(self): for fn, im in self.images.items(): self.logger.debug('{} info includes "{}"'.format( fn, im.info.keys())) name, extension = splitext(fn) if extension[1:] in HAS_PROFILE: assert_in('icc_profile', im.info.keys()) profile = getOpenProfile(BytesIO(im.info['icc_profile'])) try: expected_profile = ALT_PROFILE[fn] except KeyError: expected_profile = ( 'IEC 61966-2.1 Default RGB colour space - sRGB') assert_equal(getProfileName(profile).strip(), expected_profile) else: assert_not_in('icc_profile', im.info.keys())
def _get_profile_from_file(self, profile_name): fn = join(dirname(realpath(__file__)), 'icc', '{}.icc'.format(profile_name)) return getOpenProfile(fn)
if sys.platform == 'win32': import win32gui else: # python-gi flag HAS_GI = False try: from gi.repository import GLib, Gio, Colord HAS_GI = True except ImportError: pass if not HAS_GI: dlgWarn( "Automatic detection of monitor profile needs gi installed.\n trying to use %s instead" % DEFAULT_MONITOR_PROFILE_PATH) try: getOpenProfile(DEFAULT_MONITOR_PROFILE_PATH) except PyCMSError: dlgWarn("Invalid profile %s" % DEFAULT_MONITOR_PROFILE_PATH, info="Color management is disabled") def get_default_working_profile(): """ try to find a default image profile @return: profile @rtype: ImageCmsProfile """ try: profile = getOpenProfile(SRGB_PROFILE_PATH) except PyCMSError: dlgWarn(