Пример #1
0
def vcgt_to_cal(profile):
    """ Return a CAL (CGATS instance) from vcgt """
    cgats = CGATS.CGATS(file_identifier="CAL")
    context = cgats.add_data({"DESCRIPTOR": "Argyll Device Calibration State"})
    context.add_data({"ORIGINATOR": "vcgt"})
    context.add_data({
        "CREATED":
        strftime("%a %b %d %H:%M:%S %Y", profile.dateTime.timetuple())
    })
    context.add_keyword("DEVICE_CLASS", "DISPLAY")
    context.add_keyword("COLOR_REP", "RGB")
    context.add_keyword("RGB_I")
    key = "DATA_FORMAT"
    context[key] = CGATS.CGATS()
    context[key].key = key
    context[key].parent = context
    context[key].root = cgats
    context[key].type = key
    context[key].add_data(("RGB_I", "RGB_R", "RGB_G", "RGB_B"))
    key = "DATA"
    context[key] = CGATS.CGATS()
    context[key].key = key
    context[key].parent = context
    context[key].root = cgats
    context[key].type = key
    values = profile.tags.vcgt.getNormalizedValues()
    for i, triplet in enumerate(values):
        context[key].add_data(("%.7f" % (i / float(len(values) - 1)), ) +
                              triplet)
    return cgats
Пример #2
0
def can_update_cal(path):
    """ Check if cal can be updated by checking for required fields. """
    try:
        calstat = os.stat(path)
    except Exception as exception:
        safe_print("Warning - os.stat('%s') failed: %s" %
                   tuple(safe_unicode(s) for s in (path, exception)))
        return False
    if not path in cals or cals[path].mtime != calstat.st_mtime:
        try:
            cal = CGATS.CGATS(path)
        except (IOError, CGATS.CGATSInvalidError,
                CGATS.CGATSInvalidOperationError, CGATS.CGATSKeyError,
                CGATS.CGATSTypeError, CGATS.CGATSValueError) as exception:
            if path in cals:
                del cals[path]
            safe_print("Warning - couldn't process CGATS file '%s': %s" %
                       tuple(safe_unicode(s) for s in (path, exception)))
        else:
            if cal.queryv1("DEVICE_CLASS") == "DISPLAY" and not None in \
               (cal.queryv1("TARGET_WHITE_XYZ"),
             cal.queryv1("TARGET_GAMMA"),
             cal.queryv1("BLACK_POINT_CORRECTION"),
             cal.queryv1("QUALITY")):
                cals[path] = cal
    return path in cals and cals[path].mtime == calstat.st_mtime
Пример #3
0
def add_dispcal_options_to_cal(cal, options_dispcal):
    # Add dispcal options to cal
    options_dispcal = quote_nonoption_args(options_dispcal)
    try:
        cgats = CGATS.CGATS(cal)
        cgats[0].add_section(
            "ARGYLL_DISPCAL_ARGS",
            " ".join(options_dispcal).encode("UTF-7", "replace"))
        return cgats
    except Exception as exception:
        safe_print(safe_unicode(traceback.format_exc()))
Пример #4
0
def verify_cgats(cgats, required, ignore_unknown=True):
    """
	Verify and return a CGATS instance or None on failure.
	
	Verify if a CGATS instance has a section with all required fields. 
	Return the section as CGATS instance on success, None on failure.
	
	If ignore_unknown evaluates to True, ignore fields which are not required.
	Otherwise, the CGATS data must contain only the required fields, no more,
	no less.
	"""
    cgats_1 = cgats.queryi1(required)
    if cgats_1 and cgats_1.parent and cgats_1.parent.parent:
        cgats_1 = cgats_1.parent.parent
        if cgats_1.queryv1("NUMBER_OF_SETS"):
            if cgats_1.queryv1("DATA_FORMAT"):
                for field in required:
                    if not field in list(
                            cgats_1.queryv1("DATA_FORMAT").values()):
                        raise CGATS.CGATSKeyError(
                            "Missing required field: %s" % field)
                if not ignore_unknown:
                    for field in list(cgats_1.queryv1("DATA_FORMAT").values()):
                        if not field in required:
                            raise CGATS.CGATSError("Unknown field: %s" % field)
            else:
                raise CGATS.CGATSInvalidError("Missing DATA_FORMAT")
        else:
            raise CGATS.CGATSInvalidError("Missing NUMBER_OF_SETS")
        modified = cgats_1.modified
        cgats_1.filename = cgats.filename
        cgats_1.modified = modified
        return cgats_1
    else:
        raise CGATS.CGATSKeyError("Missing required fields: %s" %
                                  ", ".join(required))
Пример #5
0
def cal_to_vcgt(cal, return_cgats=False):
    """ 
	Create a vcgt tag from calibration data.
	
	cal must refer to a valid Argyll CAL file and can be a CGATS instance 
	or a filename.
	
	"""
    if not isinstance(cal, CGATS.CGATS):
        try:
            cal = CGATS.CGATS(cal)
        except (IOError, CGATS.CGATSInvalidError,
                CGATS.CGATSInvalidOperationError, CGATS.CGATSKeyError,
                CGATS.CGATSTypeError, CGATS.CGATSValueError) as exception:
            safe_print("Warning - couldn't process CGATS file '%s': %s" %
                       tuple(safe_unicode(s) for s in (cal, exception)))
            return None
    required_fields = ("RGB_I", "RGB_R", "RGB_G", "RGB_B")
    data_format = cal.queryv1("DATA_FORMAT")
    if data_format:
        for field in required_fields:
            if not field in list(data_format.values()):
                if debug: safe_print("[D] Missing required field:", field)
                return None
        for field in list(data_format.values()):
            if not field in required_fields:
                if debug: safe_print("[D] Unknown field:", field)
                return None
    entries = cal.queryv(required_fields)
    if len(entries) < 1:
        if debug:
            safe_print("[D] No entries found in calibration", cal.filename)
        return None
    vcgt = ICCP.VideoCardGammaTableType("", "vcgt")
    vcgt.update({
        "channels": 3,
        "entryCount": len(entries),
        "entrySize": 2,
        "data": [[], [], []]
    })
    for n in entries:
        for i in range(3):
            vcgt.data[i].append(entries[n][i + 1] * 65535.0)
    if return_cgats:
        return vcgt, cal
    return vcgt
Пример #6
0
def add_options_to_ti3(ti3, options_dispcal=None, options_colprof=None):
    # Add dispcal and colprof options to ti3
    try:
        cgats = CGATS.CGATS(ti3)
        if options_colprof:
            options_colprof = quote_nonoption_args(options_colprof)
            cgats[0].add_section(
                "ARGYLL_COLPROF_ARGS",
                " ".join(options_colprof).encode("UTF-7", "replace"))
        if options_dispcal and 1 in cgats:
            options_dispcal = quote_nonoption_args(options_dispcal)
            cgats[1].add_section(
                "ARGYLL_DISPCAL_ARGS",
                " ".join(options_dispcal).encode("UTF-7", "replace"))
        return cgats
    except Exception as exception:
        safe_print(safe_unicode(traceback.format_exc()))
Пример #7
0
def ti3_to_ti1(ti3_data):
    """
	Create and return TI1 data converted from TI3.
	
	ti3_data can be a file object, a list of strings or a string holding the data.
	
	"""
    ti3 = CGATS.CGATS(ti3_data)
    if not ti3:
        return ""
    ti3[0].type = "CTI1"
    ti3[0].DESCRIPTOR = "Argyll Calibration Target chart information 1"
    ti3[0].ORIGINATOR = "Argyll targen"
    if hasattr(ti3[0], "COLOR_REP"):
        color_rep = ti3[0].COLOR_REP.split('_')[0]
    else:
        color_rep = "RGB"
    ti3[0].add_keyword("COLOR_REP", color_rep)
    ti3[0].remove_keyword("DEVICE_CLASS")
    if hasattr(ti3[0], "LUMINANCE_XYZ_CDM2"):
        ti3[0].remove_keyword("LUMINANCE_XYZ_CDM2")
    if hasattr(ti3[0], "ARGYLL_COLPROF_ARGS"):
        del ti3[0].ARGYLL_COLPROF_ARGS
    return str(ti3[0])
Пример #8
0
    def __init__(self, parent, cgats, worker=None):
        """
		Init new CCXPlot window.

		parent   Parent window (only used for error dialogs)
		cgats    A CCMX/CCSS CGATS instance
		worker   Worker instance
		
		"""

        self.is_ccss = cgats[0].type == "CCSS"

        desc = cgats.get_descriptor()

        if cgats.filename:
            fn, ext = os.path.splitext(os.path.basename(cgats.filename))
        else:
            fn = desc
            if self.is_ccss:
                ext = ".ccss"
            else:
                ext = ".ccmx"

        desc = lang.getstr(ext[1:] + "." + fn, default=desc)

        if self.is_ccss:
            ccxx_type = "spectral"
        else:
            ccxx_type = "matrix"

        title = "%s: %s" % (lang.getstr(ccxx_type), desc)

        if self.is_ccss:
            # Convert to TI3 so we can get XYZ from spectra for coloring

            temp = worker.create_tempdir()
            if isinstance(temp, Exception):
                show_result_dialog(temp, parent)
            else:
                basename = make_filename_safe(desc)
                temp_path = os.path.join(temp, basename + ".ti3")

                cgats[0].type = "CTI3"
                cgats[0].DEVICE_CLASS = "DISPLAY"
                cgats.write(temp_path)

                temp_out_path = os.path.join(temp, basename + ".CIE.ti3")

                result = worker.exec_cmd(get_argyll_util("spec2cie"),
                                         [temp_path, temp_out_path],
                                         capture_output=True)
                if isinstance(result, Exception) or not result:
                    show_result_dialog(
                        UnloggedError(result or "".join(worker.errors)),
                        parent)
                    worker.wrapup(False)
                else:
                    try:
                        cgats = CGATS.CGATS(temp_out_path)
                    except Exception as exception:
                        show_result_dialog(exception, parent)
                    finally:
                        worker.wrapup(False)

        data_format = cgats.queryv1("DATA_FORMAT")
        data = cgats.queryv1("DATA")

        XYZ_max = 0
        self.samples = []

        if self.is_ccss:
            x_min = cgats.queryv1("SPECTRAL_START_NM")
            x_max = cgats.queryv1("SPECTRAL_END_NM")
            bands = cgats.queryv1("SPECTRAL_BANDS")
            lores = bands <= 40
            if lores:
                # Interpolate if lores
                # 1nm intervals
                steps = int(x_max - x_min) + 1
                safe_print("Up-interpolating", bands, "spectral bands to",
                           steps)
                step = (x_max - x_min) / (steps - 1.)
            else:
                step = (x_max - x_min) / (bands - 1.)
            y_min = 0
            y_max = 1

            Y_max = 0
            for i, sample in data.items():
                # Get nm and spectral power
                values = []
                x = x_min
                for k in data_format.values():
                    if k.startswith("SPEC_"):
                        y = sample[k]
                        y_min = min(y, y_min)
                        y_max = max(y, y_max)
                        if lores:
                            values.append(y)
                        else:
                            values.append((x, y))
                            x += step
                if lores:
                    # Interpolate if lores. Use Catmull-Rom instead of
                    # PolySpline as we want curves to go through points exactly
                    numvalues = len(values)
                    interp = ICCP.CRInterpolation(values)
                    values = []
                    for i in range(steps):
                        values.append(
                            (x, interp(i / (steps - 1.) * (numvalues - 1.))))
                        x += step
                # Get XYZ for colorization
                XYZ = []
                for component in "XYZ":
                    label = "XYZ_" + component
                    if label in sample:
                        v = sample[label]
                        XYZ_max = max(XYZ_max, v)
                        if label == "XYZ_Y":
                            Y_max = max(Y_max, v)
                        XYZ.append(v)
                self.samples.append((XYZ, values, {}))

            Plot = plot.PolyLine
            Plot._attributes["width"] = 1
        else:
            # CCMX
            cube_size = 2

            x_min = 0

            y_min = 0

            mtx = colormath.Matrix3x3(
                [[sample[k] for k in data_format.values()]
                 for sample in data.values()])
            imtx = mtx.inverted()

            # Get XYZ that colorimeter would measure without matrix (sRGB ref,
            # so not accurate, but useful for visual representation which is all
            # we care about here)
            if cube_size == 2:
                scale = 1
                x_max = 100 * scale
                y_max = x_max * (74.6 / 67.4)
                if sys.platform != "win32":
                    x_center = x_max / 2.
                else:
                    x_center = x_max / 2. - 2.5
                y_center = y_max / 2.
                x_center *= scale
                y_center *= scale
                pos2rgb = [((x_center - 23.7, y_center - 13.7), (0, 0, 1)),
                           ((x_center, y_center + 27.3), (0, 1, 0)),
                           ((x_center + 23.7, y_center - 13.7), (1, 0, 0)),
                           ((x_center - 23.7, y_center + 13.7), (0, 1, 1)),
                           ((x_center, y_center - 27.3), (1, 0, 1)),
                           ((x_center + 23.7, y_center + 13.7), (1, 1, 0)),
                           ((x_center, y_center), (1, 1, 1))]
                attrs_c = {'size': 10}
                attrs_r = {'size': 5}
            else:
                x_max = 100
                y_max = 100
                y = -5
                pos2rgb = []
                for R in range(cube_size):
                    for G in range(cube_size):
                        x = -5
                        y += 10
                        for B in range(cube_size):
                            x += 10
                            pos2rgb.append(((x, y), (v / (cube_size - 1.0)
                                                     for v in (R, G, B))))
                attrs_c = {'marker': 'square', 'size': 10}
                attrs_r = {'marker': 'square', 'size': 5}
            Y_max = (imtx * colormath.get_whitepoint("D65"))[1]
            for i, ((x, y), (R, G, B)) in enumerate(pos2rgb):
                XYZ = list(colormath.RGB2XYZ(R, G, B))
                X, Y, Z = imtx * XYZ
                XYZ_max = max(XYZ_max, X, Y, Z)
                self.samples.append(([X, Y, Z], [(x, y)], attrs_c))
                self.samples.append((XYZ, [(x, y)], attrs_r))

            Plot = plot.PolyMarker

        if self.is_ccss:
            # Protect against division by zero when range is zero
            if not x_max - x_min:
                x_min = 350.0
                x_max = 750.0
            if not y_max - y_min:
                y_min = 0.0
                y_max = 10.0

            y_zero = 0

            self.ccxx_axis_x = (math.floor(x_min / 50.) * 50,
                                math.ceil(x_max / 50.) * 50)
            self.spec_x = (self.ccxx_axis_x[1] - self.ccxx_axis_x[0]) / 50.
            graph_range = nicenum(y_max - y_zero, False)
            d = nicenum(graph_range / (NTICK - 1.0), True)
            self.spec_y = math.ceil(y_max / d)
            self.ccxx_axis_y = (math.floor(y_zero / d) * d, self.spec_y * d)
        else:
            self.ccxx_axis_x = (math.floor(x_min / 20.) * 20,
                                math.ceil(x_max / 20.) * 20)
            self.ccxx_axis_y = (math.floor(y_min), math.ceil(y_max))

        self.gfx = []
        for XYZ, values, attrs in self.samples:
            if len(XYZ) == 3:
                # Got XYZ
                if attrs.get("size") > 11.25:
                    # Colorimeter XYZ
                    if Y_max > 1:
                        # Colorimeter brighter than ref
                        XYZ[:] = [v / Y_max for v in XYZ]
                    else:
                        # Colorimeter dimmer than ref
                        XYZ[:] = [v * Y_max for v in XYZ]
                else:
                    # Ref XYZ
                    if Y_max > 1:
                        # Colorimeter brighter than ref
                        XYZ[:] = [v / Y_max for v in XYZ]
                RGB = tuple(
                    int(v)
                    for v in colormath.XYZ2RGB(*XYZ, scale=255, round_=True))
            else:
                RGB = (153, 153, 153)
            self.gfx.append(Plot(values, colour=wx.Colour(*RGB), **attrs))
        if self.is_ccss:
            # Add a few points at the extremes to define a bounding box
            self.gfx.append(
                plot.PolyLine(
                    [(self.ccxx_axis_x[0], self.ccxx_axis_y[0]),
                     (self.ccxx_axis_x[1], self.ccxx_axis_y[1] - y_min)],
                    colour=wx.Colour(0, 0, 0, 0)))

        ref = cgats.queryv1("REFERENCE")
        if ref:
            ref = get_canonical_instrument_name(safe_unicode(ref, "UTF-8"))

        if not self.is_ccss:
            observers_ab = {}
            for observer in config.valid_values["observer"]:
                observers_ab[observer] = lang.getstr("observer." + observer)
            x_label = [lang.getstr("matrix")]
            x_label.extend(["%9.6f %9.6f %9.6f" % tuple(row) for row in mtx])
            if ref:
                ref_observer = cgats.queryv1("REFERENCE_OBSERVER")
                if ref_observer:
                    ref += ", " + observers_ab.get(ref_observer, ref_observer)
                x_label.append("")
                x_label.append(ref)
            fit_method = cgats.queryv1("FIT_METHOD")
            if fit_method == "xy":
                fit_method = lang.getstr("ccmx.use_four_color_matrix_method")
            elif fit_method:
                fit_method = lang.getstr("perceptual")
            fit_de00_avg = cgats.queryv1("FIT_AVG_DE00")
            if not isinstance(fit_de00_avg, float):
                fit_de00_avg = None
            fit_de00_max = cgats.queryv1("FIT_MAX_DE00")
            if not isinstance(fit_de00_max, float):
                fit_de00_max = None
            if fit_method:
                x_label.append(fit_method)
            fit_de00 = []
            if fit_de00_avg:
                fit_de00.append(
                    "ΔE*00 %s %.4f" %
                    (lang.getstr("profile.self_check.avg"), fit_de00_avg))
            if fit_de00_max:
                fit_de00.append(
                    "ΔE*00 %s %.4f" %
                    (lang.getstr("profile.self_check.max"), fit_de00_max))
            if fit_de00:
                x_label.append("\n".join(fit_de00))
            x_label = "\n".join(x_label)
        else:
            x_label = ""
            if ref:
                x_label += ref + ", "
            x_label += "%.1fnm, %i-%inm" % ((x_max - x_min) /
                                            (bands - 1.0), x_min, x_max)

        scale = max(getcfg("app.dpi") / config.get_default_dpi(), 1)

        style = wx.DEFAULT_FRAME_STYLE

        wx.Frame.__init__(self, None, -1, title, style=style)
        self.SetIcons(config.get_icon_bundle([256, 48, 32, 16], appname))
        self.SetBackgroundColour(BGCOLOUR)
        self.Sizer = wx.GridSizer(1, 1, 0, 0)
        bg = wx.Panel(self)
        bg.SetBackgroundColour(BGCOLOUR)
        bg.Sizer = wx.BoxSizer(wx.VERTICAL)
        self.canvas = canvas = LUTCanvas(bg)
        if self.is_ccss:
            bg.MinSize = (513 * scale, 557 * scale)
            btnsizer = wx.BoxSizer(wx.HORIZONTAL)
            bg.Sizer.Add(btnsizer,
                         flag=wx.EXPAND | wx.TOP | wx.RIGHT | wx.LEFT,
                         border=16)
            self.toggle_btn = FlatShadedButton(bg,
                                               -1,
                                               label=lang.getstr("spectral"))
            btnsizer.Add(self.toggle_btn, 1)
            self.Sizer.Add(bg, 1, flag=wx.EXPAND)
            bg.Sizer.Add(canvas, 1, flag=wx.EXPAND)
        else:
            self.Sizer.Add(bg, flag=wx.ALIGN_CENTER)
            canvas_w = 240 * scale
            canvas.MinSize = (canvas_w, canvas_w * (74.6 / 67.4))
            bg.Sizer.Add(canvas, flag=wx.ALIGN_CENTER)
        label = wx.StaticText(bg,
                              -1,
                              x_label.replace("&", "&&"),
                              style=wx.ALIGN_CENTRE_HORIZONTAL)
        label.SetForegroundColour(FGCOLOUR)
        label.SetMaxFontSize(11)
        bg.Sizer.Add(label,
                     flag=wx.ALIGN_CENTER | wx.ALL & ~wx.TOP,
                     border=16 * scale)
        canvas.SetBackgroundColour(BGCOLOUR)
        canvas.SetEnableCenterLines(False)
        canvas.SetEnableDiagonals(False)
        canvas.SetEnableGrid(True)
        canvas.enableTicks = (True, True)
        canvas.tickPen = wx.Pen(GRIDCOLOUR, canvas._pointSize[0])
        canvas.SetEnablePointLabel(False)
        canvas.SetEnableTitle(True)
        canvas.SetForegroundColour(FGCOLOUR)
        canvas.SetGridColour(GRIDCOLOUR)
        canvas.canvas.BackgroundColour = BGCOLOUR
        if self.is_ccss:
            canvas.HandCursor = wx.StockCursor(wx.CURSOR_SIZING)
            canvas.SetCursor(canvas.HandCursor)
        else:
            canvas.canvas.Unbind(wx.EVT_LEFT_DCLICK)
            canvas.SetEnableDrag(False)
            canvas.SetCursor(wx.StockCursor(wx.CURSOR_DEFAULT))
            canvas.SetXSpec('none')
            canvas.SetYSpec('none')

        # CallAfter is needed under GTK as usual
        wx.CallAfter(self.draw_ccxx)

        if self.is_ccss:
            self.Bind(wx.EVT_KEY_DOWN, self.key_handler)
            for child in self.GetAllChildren():
                child.Bind(wx.EVT_KEY_DOWN, self.key_handler)
                child.Bind(wx.EVT_MOUSEWHEEL, self.OnWheel)

            self.toggle_btn.Bind(wx.EVT_BUTTON, self.toggle_draw)

            self.Bind(wx.EVT_SIZE, self.OnSize)
        else:
            bg.Sizer.Add((0, 16))
        self.Sizer.SetSizeHints(self)
        self.Sizer.Layout()
Пример #9
0
    print("untethered.min_delta", getcfg("untethered.min_delta"))
    print("untethered.min_delta.lightness",
          getcfg("untethered.min_delta.lightness"))
    print("untethered.max_delta.chroma", getcfg("untethered.max_delta.chroma"))
    lang.init()
    lang.update_defaults()
    app = BaseApp(0)
    app.TopWindow = UntetheredFrame(start_timer=False)
    testchart = getcfg("testchart.file")
    if os.path.splitext(testchart)[1].lower() in (".icc", ".icm"):
        try:
            testchart = ICCP.ICCProfile(testchart).tags.targ
        except:
            pass
    try:
        app.TopWindow.cgats = CGATS.CGATS(testchart)
    except:
        app.TopWindow.cgats = CGATS.CGATS("""TI1    
BEGIN_DATA_FORMAT
SAMPLE_ID RGB_R RGB_G RGB_B XYZ_X XYZ_Y XYZ_Z
END_DATA_FORMAT
BEGIN_DATA
1 0 0 0 0 0 0
END_DATA
""")
    app.TopWindow.worker = Worker()
    app.TopWindow.worker.progress_wnd = app.TopWindow
    app.TopWindow.Show()
    files = Files([app.TopWindow.worker, app.TopWindow])

    def test(bytes=None):
Пример #10
0
def extract_device_gray_primaries(ti3,
                                  gray=True,
                                  logfn=None,
                                  include_neutrals=False,
                                  neutrals_ab_threshold=0.1):
    """
	Extract gray or primaries into new TI3
	
	Return extracted ti3, extracted RGB to XYZ mapping and remaining RGB to XYZ

	"""
    filename = ti3.filename
    ti3 = ti3.queryi1("DATA")
    ti3.filename = filename
    ti3_extracted = CGATS.CGATS("""CTI3
DEVICE_CLASS "DISPLAY"
COLOR_REP "RGB_XYZ"
BEGIN_DATA_FORMAT
END_DATA_FORMAT
BEGIN_DATA
END_DATA""")[0]
    ti3_extracted.DATA_FORMAT.update(ti3.DATA_FORMAT)
    subset = [(100.0, 100.0, 100.0), (0.0, 0.0, 0.0)]
    if not gray:
        subset.extend([(100.0, 0.0, 0.0), (0.0, 100.0, 0.0), (0.0, 0.0, 100.0),
                       (50.0, 50.0, 50.0)])
        if logfn:
            logfn("Extracting neutrals and primaries from %s" % ti3.filename)
    else:
        if logfn:
            logfn("Extracting neutrals from %s" % ti3.filename)
    RGB_XYZ_extracted = OrderedDict()
    RGB_XYZ_remaining = OrderedDict()
    dupes = {}
    if include_neutrals:
        white = ti3.get_white_cie("XYZ")
        str_thresh = str(neutrals_ab_threshold)
        round_digits = len(str_thresh[str_thresh.find(".") + 1:])
    for i, item in ti3.DATA.items():
        if not i:
            # Check if fields are missing
            for prefix in ("RGB", "XYZ"):
                for suffix in prefix:
                    key = "%s_%s" % (prefix, suffix)
                    if not key in item:
                        raise Error(
                            lang.getstr("error.testchart.missing_fields",
                                        (ti3.filename, key)))
        RGB = (item["RGB_R"], item["RGB_G"], item["RGB_B"])
        XYZ = (item["XYZ_X"], item["XYZ_Y"], item["XYZ_Z"])
        for RGB_XYZ in (RGB_XYZ_extracted, RGB_XYZ_remaining):
            if RGB in RGB_XYZ:
                if RGB != (100.0, 100.0, 100.0):
                    # Add to existing values for averaging later
                    # if it's not white (all other readings are scaled to the
                    # white Y by dispread, so we don't alter it. Note that it's
                    # always the first encountered white that will have Y = 100,
                    # even if subsequent white readings may be higher)
                    XYZ = tuple(RGB_XYZ[RGB][i] + XYZ[i] for i in range(3))
                    if not RGB in dupes:
                        dupes[RGB] = 1.0
                    dupes[RGB] += 1.0
                elif RGB in subset:
                    # We have white already, remove it from the subset so any
                    # additional white readings we encounter are ignored
                    subset.remove(RGB)
        if ((gray and (item["RGB_R"] == item["RGB_G"] == item["RGB_B"] or
                       (include_neutrals and all(
                           round(abs(v), round_digits) <= neutrals_ab_threshold
                           for v in colormath.XYZ2Lab(item["XYZ_X"],
                                                      item["XYZ_Y"],
                                                      item["XYZ_Z"],
                                                      whitepoint=white)[1:])))
             and not RGB in [(100.0, 100.0, 100.0), (0.0, 0.0, 0.0)])
                or RGB in subset):
            ti3_extracted.DATA.add_data(item)
            RGB_XYZ_extracted[RGB] = XYZ
        elif not RGB in [(100.0, 100.0, 100.0), (0.0, 0.0, 0.0)]:
            RGB_XYZ_remaining[RGB] = XYZ
    for RGB, count in dupes.items():
        for RGB_XYZ in (RGB_XYZ_extracted, RGB_XYZ_remaining):
            if RGB in RGB_XYZ:
                # Average values
                XYZ = tuple(RGB_XYZ[RGB][i] / count for i in range(3))
                RGB_XYZ[RGB] = XYZ
    return ti3_extracted, RGB_XYZ_extracted, RGB_XYZ_remaining
Пример #11
0
 def chart_ctrl_handler(self, event):
     chart = self.chart_ctrl.GetPath()
     values = []
     try:
         cgats = CGATS.CGATS(chart)
     except (IOError, CGATS.CGATSInvalidError,
             CGATS.CGATSInvalidOperationError, CGATS.CGATSKeyError,
             CGATS.CGATSTypeError, CGATS.CGATSValueError) as exception:
         show_result_dialog(exception, self)
     else:
         data_format = cgats.queryv1("DATA_FORMAT")
         accurate = cgats.queryv1("ACCURATE_EXPECTED_VALUES") == "true"
         if data_format:
             basename, ext = os.path.splitext(chart)
             for column in data_format.values():
                 column_prefix = column.split("_")[0]
                 if (column_prefix in ("CMYK", "LAB", "RGB", "XYZ")
                         and column_prefix not in values
                         and (((ext.lower() == ".cie" or accurate)
                               and column_prefix in ("LAB", "XYZ")) or
                              (ext.lower() == ".ti1"
                               and column_prefix in ("CMYK", "RGB")) or
                              (ext.lower() not in (".cie", ".ti1")))):
                     values.append(column_prefix)
             if values:
                 self.panel.Freeze()
                 self.fields_ctrl.SetItems(values)
                 self.fields_ctrl.GetContainingSizer().Layout()
                 self.panel.Thaw()
                 fields = getcfg("measurement_report.chart.fields")
                 if ext.lower() == ".ti1":
                     index = 0
                 elif "RGB" in values and not ext.lower() == ".cie":
                     index = values.index("RGB")
                 elif "CMYK" in values:
                     index = values.index("CMYK")
                 elif "XYZ" in values:
                     index = values.index("XYZ")
                 elif "LAB" in values:
                     index = values.index("LAB")
                 else:
                     index = 0
                 self.fields_ctrl.SetSelection(index)
                 setcfg("measurement_report.chart", chart)
                 self.chart_patches_amount.Freeze()
                 self.chart_patches_amount.SetLabel(
                     str(cgats.queryv1("NUMBER_OF_SETS") or ""))
                 self.update_estimated_measurement_time("chart")
                 self.chart_patches_amount.GetContainingSizer().Layout()
                 self.chart_patches_amount.Thaw()
                 self.chart_white = cgats.get_white_cie()
         if not values:
             if chart:
                 show_result_dialog(
                     lang.getstr("error.testchart.missing_fields",
                                 (chart, "RGB/CMYK %s LAB/XYZ" %
                                  lang.getstr("or"))), self)
             self.chart_ctrl.SetPath(getcfg("measurement_report.chart"))
         else:
             self.chart_btn.Enable("RGB" in values)
             if self.Parent:
                 parent = self.Parent
             else:
                 parent = self
             if (event and self.chart_btn.Enabled
                     and hasattr(parent, "tcframe")
                     and self.tcframe.IsShownOnScreen()
                     and (not hasattr(parent.tcframe, "ti1")
                          or chart != parent.tcframe.ti1.filename)):
                 parent.tcframe.tc_load_cfg_from_ti1(
                     None, chart, "measurement_report.chart",
                     "mr_set_testchart")
     self.fields_ctrl.Enable(self.fields_ctrl.GetCount() > 1)
     self.fields_ctrl_handler(event)
Пример #12
0
 def __init__(self,
              profile,
              intent="r",
              direction="f",
              order="n",
              pcs=None,
              scale=1,
              cwd=None,
              startupinfo=None,
              use_icclu=False,
              use_cam_clipping=False,
              logfile=None,
              worker=None,
              show_actual_if_clipped=False,
              input_encoding=None,
              output_encoding=None,
              convert_video_rgb_to_clut65=False,
              verbose=1):
     if not profile:
         raise Error("Xicclu: Profile is %r" % profile)
     WorkerBase.__init__(self)
     self.scale = scale
     self.convert_video_rgb_to_clut65 = convert_video_rgb_to_clut65
     self.logfile = logfile
     self.worker = worker
     self.temp = False
     utilname = "icclu" if use_icclu else "xicclu"
     xicclu = get_argyll_util(utilname)
     if not xicclu:
         raise Error(lang.getstr("argyll.util.not_found", utilname))
     if not isinstance(profile, (CGATS.CGATS, ICCP.ICCProfile)):
         if profile.lower().endswith(".cal"):
             profile = CGATS.CGATS(profile)
         else:
             profile = ICCP.ICCProfile(profile)
     is_profile = isinstance(profile, ICCP.ICCProfile)
     if (is_profile and profile.version >= 4
             and not profile.convert_iccv4_tags_to_iccv2()):
         raise Error("\n".join([
             lang.getstr("profile.iccv4.unsupported"),
             profile.getDescription()
         ]))
     if not profile.fileName or not os.path.isfile(profile.fileName):
         if profile.fileName:
             prefix = os.path.basename(profile.fileName)
         elif is_profile:
             prefix = make_filename_safe(profile.getDescription(),
                                         concat=False) + profile_ext
         else:
             # CGATS (.cal)
             prefix = "cal"
         prefix += "-"
         if not cwd:
             cwd = self.create_tempdir()
             if isinstance(cwd, Exception):
                 raise cwd
         fd, profile.fileName = tempfile.mkstemp("", prefix, dir=cwd)
         stream = os.fdopen(fd, "wb")
         profile.write(stream)
         stream.close()
         self.temp = True
     elif not cwd:
         cwd = os.path.dirname(profile.fileName)
     profile_basename = safe_unicode(os.path.basename(profile.fileName))
     profile_path = profile.fileName
     if sys.platform == "win32":
         profile_path = win32api.GetShortPathName(profile_path)
     self.profile_path = safe_str(profile_path)
     if sys.platform == "win32" and not startupinfo:
         startupinfo = sp.STARTUPINFO()
         startupinfo.dwFlags |= sp.STARTF_USESHOWWINDOW
         startupinfo.wShowWindow = sp.SW_HIDE
     xicclu = safe_str(xicclu)
     cwd = safe_str(cwd)
     self.verbose = verbose
     args = [xicclu, "-v%i" % verbose, "-s%s" % scale]
     self.show_actual_if_clipped = False
     if utilname == "xicclu":
         if (is_profile and show_actual_if_clipped
                 and "A2B0" in profile.tags
                 and ("B2A0" in profile.tags or direction == "if")):
             args.append("-a")
             self.show_actual_if_clipped = True
         if use_cam_clipping:
             args.append("-b")
         if get_argyll_version("xicclu") >= [1, 6]:
             # Add encoding parameters
             # Note: Not adding -e -E can cause problems due to unitialized
             # in_tvenc and out_tvenc variables in xicclu.c for Argyll 1.6.x
             if not input_encoding:
                 input_encoding = "n"
             if not output_encoding:
                 output_encoding = "n"
             args += [
                 "-e" + safe_str(input_encoding),
                 "-E" + safe_str(output_encoding)
             ]
     args.append("-f" + direction)
     self.output_scale = 1.0
     if is_profile:
         if profile.profileClass not in ("abst", "link"):
             args.append("-i" + intent)
             if order != "n":
                 args.append("-o" + order)
         if profile.profileClass != "link":
             if (direction in ("f", "ib") and
                 (pcs == "x" or
                  (profile.connectionColorSpace == "XYZ" and not pcs))):
                 # In case of forward lookup with XYZ PCS, use 0..100 scaling
                 # internally so we get extra precision from xicclu for the
                 # decimal part. Scale back to 0..1 later.
                 pcs = "X"
                 self.output_scale = 100.0
             if pcs:
                 args.append("-p" + pcs)
     args.append(self.profile_path)
     if debug or verbose > 1:
         self.sessionlogfile = LogFile(profile_basename + ".xicclu",
                                       os.path.dirname(profile.fileName))
         if is_profile:
             profile_act = ICCP.ICCProfile(profile.fileName)
             self.sessionlogfile.write(
                 "Profile ID %s (actual %s)" % (hexlify(
                     profile.ID), hexlify(profile_act.calculateID(False))))
         if cwd:
             self.log(lang.getstr("working_dir"))
             indent = "  "
             for name in cwd.split(os.path.sep):
                 self.log(
                     textwrap.fill(name + os.path.sep,
                                   80,
                                   expand_tabs=False,
                                   replace_whitespace=False,
                                   initial_indent=indent,
                                   subsequent_indent=indent))
                 indent += " "
             self.log("")
         self.log(lang.getstr("commandline"))
         printcmdline(xicclu, args[1:], fn=self.log, cwd=cwd)
         self.log("")
     self.startupinfo = startupinfo
     self.args = args
     self.cwd = cwd
     self.spawn()