예제 #1
0
 def __init__(self, filename, parent=None):
     super(MetadataWidget, self).__init__(parent)
     table = []
     last = None
     with exiftool.ExifTool(exiftool_exe()) as et:
         metadata = et.get_metadata(filename)
         for tag, value in metadata.items():
             ignore = [
                 'SourceFile', 'ExifTool:ExifTool', 'File:FileName',
                 'File:Directory', 'File:FileSize', 'File:FileModifyDate',
                 'File:FileInodeChangeDate', 'File:FileAccessDate',
                 'File:FileType', 'File:FilePermissions',
                 'File:FileTypeExtension', 'File:MIMEType'
             ]
             if not value or any(t in tag for t in ignore):
                 continue
             value = str(value).replace(', use -b option to extract', '')
             group, desc = tag.split(':')
             if last is None or group != last:
                 table.append([group, desc, value])
                 last = group
             else:
                 table.append([None, desc, value])
     headers = [self.tr('Group'), self.tr('Description'), self.tr('Value')]
     table_widget = TableWidget(table, headers)
     main_layout = QVBoxLayout()
     main_layout.addWidget(table_widget)
     self.setLayout(main_layout)
     self.setMinimumSize(620, 500)
예제 #2
0
 def __init__(self, filename, parent=None):
     super(LocationWidget, self).__init__(parent)
     self.temp_dir = QTemporaryDir()
     if self.temp_dir.isValid():
         with exiftool.ExifTool(exiftool_exe()) as et:
             try:
                 metadata = et.get_metadata(filename)
                 lat = metadata["Composite:GPSLatitude"]
                 lon = metadata["Composite:GPSLongitude"]
             except KeyError:
                 label = QLabel(self.tr("Geolocation data not found!"))
                 modify_font(label, bold=True)
                 label.setStyleSheet("color: #FF0000")
                 label.setAlignment(Qt.AlignCenter)
                 layout = QVBoxLayout()
                 layout.addWidget(label)
                 self.setLayout(layout)
                 return
             url = f"https://www.google.com/maps/place/{lat},{lon}/@{lat},{lon},17z/" \
                   f"data=!4m5!3m4!1s0x0:0x0!8m2!3d{lat}!4d{lon}"
             web_view = QWebEngineView()
             web_view.load(QUrl(url))
             layout = QVBoxLayout()
             layout.addWidget(web_view)
             self.setLayout(layout)
예제 #3
0
 def __init__(self, filename, parent=None):
     super(LocationWidget, self).__init__(parent)
     self.temp_dir = QTemporaryDir()
     if self.temp_dir.isValid():
         with exiftool.ExifTool(exiftool_exe()) as et:
             temp_file = os.path.join(self.temp_dir.path(), "geo.html")
             metadata = et.get_metadata(filename)
             try:
                 lat = metadata["Composite:GPSLatitude"]
                 long = metadata["Composite:GPSLongitude"]
             except KeyError:
                 label = QLabel(self.tr("Geolocation data not found!"))
                 modify_font(label, bold=True)
                 label.setStyleSheet("color: #FF0000")
                 label.setAlignment(Qt.AlignCenter)
                 layout = QVBoxLayout()
                 layout.addWidget(label)
                 self.setLayout(layout)
                 return
             html = '<iframe src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d2948.532014673314!2d{}!3d{}!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x0%3A0x0!2zNDLCsDIxJzA5LjAiTiA3McKwMDUnMjguMiJX!5e0!3m2!1sit!2sit!4v1590074026898!5m2!1sit!2sit" width="600" height="450" frameborder="0" style="border:0;" allowfullscreen="" aria-hidden="false" tabindex="0"></iframe>'.format(
                 long, lat)
             with open(temp_file, "w") as file:
                 file.write(html)
             web_view = QWebEngineView()
             web_view.load(QUrl("file://" + temp_file))
             layout = QVBoxLayout()
             layout.addWidget(web_view)
             self.setLayout(layout)
예제 #4
0
 def __init__(self, filename, parent=None):
     super(StructureWidget, self).__init__(parent)
     self.temp_dir = QTemporaryDir()
     if self.temp_dir.isValid():
         temp_file = os.path.join(self.temp_dir.path(), 'structure.html')
         p = run([exiftool_exe(), '-htmldump0', filename], stdout=PIPE)
         with open(temp_file, 'w') as file:
             file.write(p.stdout.decode('utf-8'))
         web_view = QWebEngineView()
         web_view.load(QUrl('file://' + temp_file))
         layout = QVBoxLayout()
         layout.addWidget(web_view)
         self.setLayout(layout)
예제 #5
0
파일: header.py 프로젝트: nsidere/sherloq
 def __init__(self, filename, parent=None):
     super(HeaderWidget, self).__init__(parent)
     self.temp_dir = QTemporaryDir()
     if self.temp_dir.isValid():
         temp_file = os.path.join(self.temp_dir.path(), "structure.html")
         p = run([exiftool_exe(), "-htmldump0", filename], stdout=PIPE)
         with open(temp_file, "w") as file:
             file.write(p.stdout.decode("utf-8"))
         web_view = QWebEngineView()
         web_view.load(QUrl("file://" + temp_file))
         layout = QVBoxLayout()
         layout.addWidget(web_view)
         self.setLayout(layout)
         self.setMinimumWidth(900)
예제 #6
0
    def __init__(self, filename, image, parent=None):
        super(ThumbWidget, self).__init__(parent)

        temp_file = QTemporaryFile()
        if temp_file.open():
            output = subprocess.check_output(
                [exiftool_exe(), '-b', '-ThumbnailImage', filename])
            temp_name = temp_file.fileName()
            with open(temp_name, 'wb') as file:
                file.write(output)
            thumb = cv.imread(temp_name, cv.IMREAD_COLOR)
            if thumb is None:
                self.show_error(self.tr('Thumbnail image not found!'))
                return
            # resized = cv.resize(image, thumb.shape[:-1][::-1], interpolation=cv.INTER_AREA)
            resized = cv.resize(thumb,
                                image.shape[:-1][::-1],
                                interpolation=cv.INTER_LANCZOS4)
            diff = cv.absdiff(image, resized)

            # image_aspect = image.shape[1] / image.shape[0]
            # thumb_aspect = thumb.shape[1] / thumb.shape[0]
            # if thumb_aspect < image_aspect:
            #     shape = (thumb.shape[1] // image_aspect, thumb.shape[1])
            # elif thumb_aspect > image_aspect:
            #     shape = (thumb.shape[0], thumb.shape[0] * image_aspect)
            # else:
            #     shape = thumb.shape
            # resized = cv.resize(image, shape, None, 0, 0, interpolation=cv.INTER_AREA)
            # top = (thumb.shape[0] - resized.shape[0]) / 2
            # bottom = top
            # left = (thumb.shape[1] - resized.shape[1]) / 2
            # right = left
            # padded = cv.copyMakeBorder(resized, top, bottom, left, right, cv.BORDER_CONSTANT)
            # if padded.shape != thumb.shape:
            #     padded = cv.resize(padded, thumb.shape, interpolation=cv.INTER_AREA)
            # diff = cv.cvtColor(cv.absdiff(thumb, padded), cv.COLOR_BGR2GRAY)

            viewer = ImageViewer(resized, diff)
            layout = QVBoxLayout()
            layout.addWidget(viewer)
            self.setLayout(layout)
예제 #7
0
파일: exif.py 프로젝트: nsidere/sherloq
 def __init__(self, filename, parent=None):
     super(ExifWidget, self).__init__(parent)
     table = []
     last = None
     with exiftool.ExifTool(exiftool_exe()) as et:
         metadata = et.get_metadata(filename)
         for tag, value in metadata.items():
             ignore = [
                 "SourceFile",
                 "ExifTool:ExifTool",
                 "File:FileName",
                 "File:Directory",
                 "File:FileSize",
                 "File:FileModifyDate",
                 "File:FileInodeChangeDate",
                 "File:FileAccessDate",
                 "File:FileType",
                 "File:FilePermissions",
                 "File:FileTypeExtension",
                 "File:MIMEType",
             ]
             if not value or any(t in tag for t in ignore):
                 continue
             value = str(value).replace(", use -b option to extract", "")
             value = value.replace("Binary data ", "Binary data: ")
             group, desc = tag.split(":")
             if last is None or group != last:
                 table.append([group, desc, value])
                 last = group
             else:
                 table.append([None, desc, value])
     headers = [self.tr("Group"), self.tr("Description"), self.tr("Value")]
     table_widget = TableWidget(table, headers)
     main_layout = QVBoxLayout()
     main_layout.addWidget(table_widget)
     self.setLayout(main_layout)
     self.setMinimumSize(740, 500)
예제 #8
0
파일: quality.py 프로젝트: nsidere/sherloq
    def __init__(self, filename, image, parent=None):
        super(QualityWidget, self).__init__(parent)

        x = np.arange(1, 101)
        y = loss_curve(image)
        tail = 5
        qm = np.argmin(y[:-tail]) + 1
        if qm == 100 - tail:
            qm = 100

        figure = Figure()
        canvas = FigureCanvas(figure)
        axes = canvas.figure.subplots()
        axes.plot(x, y * 100, label="compression loss")
        axes.fill_between(x, y * 100, alpha=0.2)
        axes.axvline(qm,
                     linestyle=":",
                     color="k",
                     label=f"min error (q = {qm})")
        xt = axes.get_xticks()
        xt = np.append(xt, 1)
        axes.set_xticks(xt)
        axes.set_xlim([1, 100])
        axes.set_ylim([0, 100])
        axes.set_xlabel(self.tr("JPEG quality (%)"))
        axes.set_ylabel(self.tr("average error (%)"))
        axes.grid(True, which="both")
        axes.legend(loc="upper center")
        axes.figure.canvas.draw()
        figure.set_tight_layout(True)

        main_layout = QVBoxLayout()
        main_layout.addWidget(canvas)

        MRK = b"\xFF"
        SOI = b"\xD8"
        DQT = b"\xDB"
        # DHT = b'\xC4'
        MSK = b"\x0F"
        PAD = b"\x00"

        MAX_TABLES = 2
        LEN_OFFSET = 2
        LUMA_IDX = 0
        CHROMA_IDX = 1

        luma = np.zeros((DCT_SIZE, DCT_SIZE), dtype=int)
        chroma = np.zeros((DCT_SIZE, DCT_SIZE), dtype=int)
        temp_file = QTemporaryFile()
        try:
            if temp_file.open():
                copyfile(filename, temp_file.fileName())
                subprocess.run(
                    [
                        exiftool_exe(), "-all=", "-overwrite_original",
                        temp_file.fileName()
                    ],
                    stdout=subprocess.DEVNULL,
                    stderr=subprocess.DEVNULL,
                )
                found = False
                with open(temp_file.fileName(), "rb") as file:
                    first = file.read(1)
                    if first not in [MRK, SOI]:
                        raise ValueError(self.tr("File is not a JPEG image!"))
                    while True:
                        if not self.find_next(file, [MRK, DQT, PAD]):
                            break
                        length = file.read(1)[0] - LEN_OFFSET
                        if length <= 0 or length % (TABLE_SIZE + 1) != 0:
                            continue
                        while length > 0:
                            mode = file.read(1)
                            if not mode:
                                break
                            index = mode[0] & MSK[0]
                            if index >= MAX_TABLES:
                                break
                            length -= 1
                            for k in range(TABLE_SIZE):
                                b = file.read(1)[0]
                                if not b:
                                    break
                                length -= 1
                                i, j = ZIG_ZAG[k]
                                if index == LUMA_IDX:
                                    luma[i, j] = b
                                elif index == CHROMA_IDX:
                                    chroma[i, j] = b
                            else:
                                found = True
            if not found:
                raise ValueError(self.tr("Unable to find JPEG tables!"))

            levels = [(1 - (np.mean(t.ravel()[1:]) - 1) / 254) * 100
                      for t in [luma, chroma]]
            distance = np.zeros(101)
            for qm in range(101):
                lu, ch = cv.split(get_tables(qm))
                lu_diff = np.mean(cv.absdiff(luma, lu))
                ch_diff = np.mean(cv.absdiff(chroma, ch))
                distance[qm] = (lu_diff + 2 * ch_diff) / 3
            closest = np.argmin(distance)
            deviation = distance[closest]
            if deviation == 0:
                quality = closest
                message = "(standard tables)"
            else:
                quality = int(np.round(closest - deviation))
                message = f"(deviation from standard tables = {deviation:.4f})"
            if quality == 0:
                quality = 1
            quality_label = QLabel(
                self.tr(
                    f"[JPEG FORMAT] Last saved quality: {quality}% {message}"))
            modify_font(quality_label, bold=True)

            luma_label = QLabel(
                self.
                tr(f"Luminance Quantization Table (level = {levels[0]:.2f}%)\n"
                   ))
            luma_label.setAlignment(Qt.AlignCenter)
            modify_font(luma_label, underline=True)
            luma_table = self.create_table(luma)
            luma_table.setFixedSize(420, 190)

            chroma_label = QLabel(
                self.
                tr(f"Chrominance Quantization Table (level = {levels[1]:.2f}%)\n"
                   ))
            chroma_label.setAlignment(Qt.AlignCenter)
            modify_font(chroma_label, underline=True)
            chroma_table = self.create_table(chroma)
            chroma_table.setFixedSize(420, 190)

            table_layout = QGridLayout()
            table_layout.addWidget(luma_label, 0, 0)
            table_layout.addWidget(luma_table, 1, 0)
            table_layout.addWidget(chroma_label, 0, 1)
            table_layout.addWidget(chroma_table, 1, 1)
            table_layout.addWidget(quality_label, 2, 0, 1, 2)
            main_layout.addLayout(table_layout)

        except ValueError:
            modelfile = "models/jpeg_qf.mdl"
            try:
                model = load(modelfile)
                limit = model.best_ntree_limit if hasattr(
                    model, "best_ntree_limit") else None
                # f = self.get_features(image)
                # p = model.predict_proba(f, ntree_limit=limit)[0, 0]
                qp = model.predict(np.reshape(y, (1, len(y))),
                                   ntree_limit=limit)[0]
                # if p > 0.5:
                #     p = 2 * (p - 0.5) * 100
                #     output = self.tr('Uncompressed image (p = {:.2f}%)'.format(p))
                # else:
                #     p = (1 - 2 * p) * 100
                #     output = self.tr('Compressed image (p = {:.2f}%) ---> Estimated JPEG quality = {}%'.format(p, qm))
                message = self.tr(
                    f"[LOSSLESS FORMAT] Estimated last saved quality = {qp:.1f}%{'' if qp <= 99 else ' (uncompressed)'}"
                )
                if qp == 100:
                    message += " (uncompressed)"
                prob_label = QLabel(message)
                modify_font(prob_label, bold=True)
                main_layout.addWidget(prob_label)
            except FileNotFoundError:
                QMessageBox.critical(
                    self, self.tr("Error"),
                    self.tr(f'Model not found ("{modelfile}")!'))

        main_layout.addStretch()
        self.setLayout(main_layout)
예제 #9
0
    def __init__(self, filename, parent=None):
        super(QualityWidget, self).__init__(parent)

        MRK = b'\xFF'
        SOI = b'\xD8'
        DQT = b'\xDB'
        # DHT = b'\xC4'
        MSK = b'\x0F'
        PAD = b'\x00'

        MAX_TABLES = 2
        LEN_OFFSET = 2
        LUMA_IDX = 0
        CHROMA_IDX = 1

        luma = np.zeros((DCT_SIZE, DCT_SIZE), dtype=int)
        chroma = np.zeros((DCT_SIZE, DCT_SIZE), dtype=int)
        temp_file = QTemporaryFile()
        if temp_file.open():
            copyfile(filename, temp_file.fileName())
            subprocess.run([
                exiftool_exe(), '-all=', '-overwrite_original',
                temp_file.fileName()
            ],
                           stdout=subprocess.DEVNULL,
                           stderr=subprocess.DEVNULL)
            found = False
            with open(temp_file.fileName(), 'rb') as file:
                first = file.read(1)
                if first not in [MRK, SOI]:
                    self.show_error(self.tr('File is not a JPEG image!'))
                    return
                while True:
                    if not self.find_next(file, [MRK, DQT, PAD]):
                        break
                    length = file.read(1)[0] - LEN_OFFSET
                    if length <= 0 or length % (TABLE_SIZE + 1) != 0:
                        continue
                    while length > 0:
                        mode = file.read(1)
                        if not mode:
                            break
                        index = mode[0] & MSK[0]
                        if index >= MAX_TABLES:
                            break
                        length -= 1
                        for k in range(TABLE_SIZE):
                            b = file.read(1)[0]
                            if not b:
                                break
                            length -= 1
                            i, j = ZIG_ZAG[k]
                            if index == LUMA_IDX:
                                luma[i, j] = b
                            elif index == CHROMA_IDX:
                                chroma[i, j] = b
                        else:
                            found = True
        if not found:
            self.show_error(self.tr('Unable to find JPEG tables!'))
            return

        levels = [(1 - (np.mean(t.ravel()[1:]) - 1) / 254) * 100
                  for t in [luma, chroma]]
        distance = np.zeros(101)
        for q in range(101):
            lu, ch = cv.split(get_tables(q))
            lu_diff = np.mean(cv.absdiff(luma, lu))
            ch_diff = np.mean(cv.absdiff(chroma, ch))
            distance[q] = (lu_diff + 2 * ch_diff) / 3
        closest = np.argmin(distance)
        deviation = distance[closest]
        if deviation == 0:
            quality = closest
            message = '(standard tables)'
        else:
            quality = int(np.round(closest - deviation))
            message = '(deviation from standard = {:.4f})'.format(deviation)
        quality_label = QLabel(
            self.tr('Last saved JPEG quality: {}% {}'.format(quality,
                                                             message)))
        modify_font(quality_label, bold=True)

        luma_label = QLabel(
            self.tr('Luminance Quantization Table (level = {:.2f}%)\n'.format(
                levels[0])))
        luma_label.setAlignment(Qt.AlignCenter)
        modify_font(luma_label, underline=True)
        luma_table = self.create_table(luma)
        luma_table.setMaximumHeight(200)
        chroma_label = QLabel(
            self.tr(
                'Chrominance Quantization Table (level = {:.2f}%)\n'.format(
                    levels[1])))
        chroma_label.setAlignment(Qt.AlignCenter)
        modify_font(chroma_label, underline=True)
        chroma_table = self.create_table(chroma)
        chroma_table.setMaximumHeight(200)

        main_layout = QGridLayout()
        main_layout.addWidget(luma_label, 0, 0)
        main_layout.addWidget(luma_table, 1, 0)
        main_layout.addWidget(chroma_label, 0, 1)
        main_layout.addWidget(chroma_table, 1, 1)
        main_layout.addWidget(quality_label, 2, 0, 1, 2)
        self.setLayout(main_layout)
        self.setFixedSize(880, 270)
예제 #10
0
    def __init__(self, filename, parent=None):
        super(QualityWidget, self).__init__(parent)

        MRK = b'\xFF'
        SOI = b'\xD8'
        DQT = b'\xDB'
        # DHT = b'\xC4'
        MSK = b'\x0F'
        PAD = b'\x00'

        MAX_TABLES = 2
        LEN_OFFSET = 2
        LUMA_IDX = 0
        CHROMA_IDX = 1

        luma = np.zeros((DCT_SIZE, DCT_SIZE), dtype=int)
        chroma = np.zeros((DCT_SIZE, DCT_SIZE), dtype=int)
        temp_file = QTemporaryFile()
        if temp_file.open():
            copyfile(filename, temp_file.fileName())
            subprocess.run([
                exiftool_exe(), '-all=', '-overwrite_original',
                temp_file.fileName()
            ],
                           stdout=subprocess.DEVNULL,
                           stderr=subprocess.DEVNULL)
            found = False
            with open(temp_file.fileName(), 'rb') as file:
                first = file.read(1)
                if first not in [MRK, SOI]:
                    self.show_error(self.tr('File is not a JPEG image!'))
                    return
                while True:
                    if not self.find_next(file, [MRK, DQT, PAD]):
                        break
                    length = file.read(1)[0] - LEN_OFFSET
                    if length <= 0 or length % (TABLE_SIZE + 1) != 0:
                        continue
                    while length > 0:
                        mode = file.read(1)
                        if not mode:
                            break
                        index = mode[0] & MSK[0]
                        if index >= MAX_TABLES:
                            break
                        length -= 1
                        for k in range(TABLE_SIZE):
                            b = file.read(1)[0]
                            if not b:
                                break
                            length -= 1
                            i, j = ZIG_ZAG[k]
                            if index == LUMA_IDX:
                                luma[i, j] = b
                            elif index == CHROMA_IDX:
                                chroma[i, j] = b
                        else:
                            found = True
        if not found:
            self.show_error(self.tr('Unable to find JPEG tables!'))
            return

        tables = np.concatenate(
            (luma[:, :, np.newaxis], chroma[:, :, np.newaxis]), axis=2)
        levels = [0, 0]
        for i in range(2):
            table = tables[:, :, i]
            mean = (np.mean(table) * TABLE_SIZE - table[0, 0]) / (TABLE_SIZE -
                                                                  1)
            levels[i] = (1 - mean / 255) * 100
            if levels[i] > 99.6:
                levels[i] = 100
        profile = [np.mean(np.abs(tables - get_tables(q))) for q in range(101)]
        quality = np.argmin(profile)

        luma_label = QLabel(
            self.tr('Luminance Quantization Table (level = {:.2f}%)\n'.format(
                levels[0])))
        luma_label.setAlignment(Qt.AlignCenter)
        modify_font(luma_label, underline=True)
        luma_table = self.create_table(luma)
        chroma_label = QLabel(
            self.tr(
                'Chrominance Quantization Table (level = {:.2f}%)\n'.format(
                    levels[1])))
        chroma_label.setAlignment(Qt.AlignCenter)
        modify_font(chroma_label, underline=True)
        chroma_table = self.create_table(chroma)

        quality_label = QLabel(
            self.tr(
                'Estimated JPEG quality (last save) = {}%'.format(quality)))
        modify_font(quality_label, bold=True)
        deviation_label = QLabel(
            self.tr('(average deviation from standard tables = {:.2f})'.format(
                profile[quality])))
        modify_font(deviation_label, italic=True)
        deviation_label.setAlignment(Qt.AlignRight)

        main_layout = QGridLayout()
        main_layout.addWidget(luma_label, 0, 0)
        main_layout.addWidget(luma_table, 1, 0)
        main_layout.addWidget(chroma_label, 0, 1)
        main_layout.addWidget(chroma_table, 1, 1)
        main_layout.addWidget(quality_label, 2, 0)
        main_layout.addWidget(deviation_label, 2, 1)
        self.setLayout(main_layout)
        self.setMinimumSize(890, 270)