mirror of
https://github.com/Kilian/Trimage.git
synced 2026-01-26 10:08:40 -05:00
commit
be7fe35ba9
2 changed files with 37 additions and 45 deletions
|
|
@ -3,26 +3,22 @@
|
||||||
import time
|
import time
|
||||||
import sys
|
import sys
|
||||||
import errno
|
import errno
|
||||||
from os import listdir
|
from os import listdir, path, remove, access, W_OK
|
||||||
from os import path
|
|
||||||
from os import remove
|
|
||||||
from os import access
|
|
||||||
from os import W_OK as WRITEABLE
|
|
||||||
from shutil import copy
|
from shutil import copy
|
||||||
from subprocess import call, PIPE
|
from subprocess import call, PIPE
|
||||||
from optparse import OptionParser
|
from optparse import OptionParser
|
||||||
|
from multiprocessing import cpu_count
|
||||||
|
from queue import Queue
|
||||||
|
|
||||||
from PyQt5.QtCore import *
|
from PyQt5.QtCore import *
|
||||||
from PyQt5.QtGui import *
|
from PyQt5.QtGui import *
|
||||||
from PyQt5.QtWidgets import *
|
from PyQt5.QtWidgets import *
|
||||||
|
|
||||||
from tools import human_readable_size
|
from tools import human_readable_size
|
||||||
from queue import Queue
|
|
||||||
from ThreadPool import ThreadPool
|
from ThreadPool import ThreadPool
|
||||||
from multiprocessing import cpu_count
|
|
||||||
|
|
||||||
from ui import Ui_trimage
|
from ui import Ui_trimage
|
||||||
|
|
||||||
|
|
||||||
VERSION = "1.0.5"
|
VERSION = "1.0.5"
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -44,11 +40,11 @@ class StartQT5(QMainWindow):
|
||||||
if self.settings.value("geometry"):
|
if self.settings.value("geometry"):
|
||||||
self.restoreGeometry(self.settings.value("geometry"))
|
self.restoreGeometry(self.settings.value("geometry"))
|
||||||
|
|
||||||
# check if apps are installed
|
# check if dependencies are installed
|
||||||
if self.checkapps():
|
if not self.check_dependencies():
|
||||||
quit()
|
quit()
|
||||||
|
|
||||||
#add quit shortcut
|
# add quit shortcut
|
||||||
if hasattr(QKeySequence, "Quit"):
|
if hasattr(QKeySequence, "Quit"):
|
||||||
self.quit_shortcut = QShortcut(QKeySequence(QKeySequence.Quit),
|
self.quit_shortcut = QShortcut(QKeySequence(QKeySequence.Quit),
|
||||||
self)
|
self)
|
||||||
|
|
@ -190,7 +186,7 @@ class StartQT5(QMainWindow):
|
||||||
|
|
||||||
def walk(self, dir, delegatorlist):
|
def walk(self, dir, delegatorlist):
|
||||||
"""
|
"""
|
||||||
Walks a directory, and executes a callback on each file
|
Walks a directory, and executes a callback on each file.
|
||||||
"""
|
"""
|
||||||
dir = path.abspath(dir)
|
dir = path.abspath(dir)
|
||||||
for file in [file for file in listdir(dir) if not file in [".","..",".svn",".git",".hg",".bzr",".cvs"]]:
|
for file in [file for file in listdir(dir) if not file in [".","..",".svn",".git",".hg",".bzr",".cvs"]]:
|
||||||
|
|
@ -203,7 +199,7 @@ class StartQT5(QMainWindow):
|
||||||
|
|
||||||
def add_image(self, fullpath, delegatorlist):
|
def add_image(self, fullpath, delegatorlist):
|
||||||
"""
|
"""
|
||||||
Adds an image file to the delegator list and update the tray and the title of the window
|
Adds an image file to the delegator list and update the tray and the title of the window.
|
||||||
"""
|
"""
|
||||||
image = Image(fullpath)
|
image = Image(fullpath)
|
||||||
if image.valid:
|
if image.valid:
|
||||||
|
|
@ -256,33 +252,27 @@ class StartQT5(QMainWindow):
|
||||||
if QSystemTrayIcon.isSystemTrayAvailable() and not self.cli:
|
if QSystemTrayIcon.isSystemTrayAvailable() and not self.cli:
|
||||||
self.systemtray.recompress.setEnabled(True)
|
self.systemtray.recompress.setEnabled(True)
|
||||||
|
|
||||||
def checkapps(self):
|
def check_dependencies(self):
|
||||||
"""Check if the required command line apps exist."""
|
"""Check if the required command line apps exist."""
|
||||||
exe = ".exe" if (sys.platform == "win32") else ""
|
exe = ".exe" if (sys.platform == "win32") else ""
|
||||||
|
status = True
|
||||||
|
dependencies = {
|
||||||
|
"jpegoptim": "--version",
|
||||||
|
"optipng": "-v",
|
||||||
|
"advpng": "--version",
|
||||||
|
"pngcrush": "-version"
|
||||||
|
}
|
||||||
|
|
||||||
|
for elt in dependencies:
|
||||||
|
retcode = self.safe_call(elt + exe + " " + dependencies[elt])
|
||||||
|
if retcode != 0:
|
||||||
status = False
|
status = False
|
||||||
retcode = self.safe_call("jpegoptim" + exe + " --version")
|
print("[error] please install {}".format(elt), file=sys.stderr)
|
||||||
if retcode != 0:
|
|
||||||
status = True
|
|
||||||
print("[error] please install jpegoptim", file=sys.stderr)
|
|
||||||
|
|
||||||
retcode = self.safe_call("optipng" + exe + " -v")
|
|
||||||
if retcode != 0:
|
|
||||||
status = True
|
|
||||||
print("[error] please install optipng", file=sys.stderr)
|
|
||||||
|
|
||||||
retcode = self.safe_call("advpng" + exe + " --version")
|
|
||||||
if retcode != 0:
|
|
||||||
status = True
|
|
||||||
print("[error] please install advancecomp", file=sys.stderr)
|
|
||||||
|
|
||||||
retcode = self.safe_call("pngcrush" + exe + " -version")
|
|
||||||
if retcode != 0:
|
|
||||||
status = True
|
|
||||||
print("[error] please install pngcrush", file=sys.stderr)
|
|
||||||
return status
|
return status
|
||||||
|
|
||||||
def safe_call(self, command):
|
def safe_call(self, command):
|
||||||
""" cross-platform command-line check """
|
"""Cross-platform command-line check."""
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
return call(command, shell=True, stdout=PIPE)
|
return call(command, shell=True, stdout=PIPE)
|
||||||
|
|
@ -352,7 +342,7 @@ class TriTableModel(QAbstractTableModel):
|
||||||
class ImageRow:
|
class ImageRow:
|
||||||
|
|
||||||
def __init__(self, image, waitingIcon=None):
|
def __init__(self, image, waitingIcon=None):
|
||||||
""" Build the information visible in the table image row. """
|
"""Build the information visible in the table image row."""
|
||||||
self.image = image
|
self.image = image
|
||||||
d = {
|
d = {
|
||||||
'shortname': lambda i: self.statusStr() % i.shortname,
|
'shortname': lambda i: self.statusStr() % i.shortname,
|
||||||
|
|
@ -374,7 +364,7 @@ class ImageRow:
|
||||||
self.d = d
|
self.d = d
|
||||||
|
|
||||||
def statusStr(self):
|
def statusStr(self):
|
||||||
""" Set the status message. """
|
"""Set the status message."""
|
||||||
if self.image.failed:
|
if self.image.failed:
|
||||||
return "ERROR: %s"
|
return "ERROR: %s"
|
||||||
if self.image.compressing:
|
if self.image.compressing:
|
||||||
|
|
@ -393,11 +383,11 @@ class ImageRow:
|
||||||
class Image:
|
class Image:
|
||||||
|
|
||||||
def __init__(self, fullpath):
|
def __init__(self, fullpath):
|
||||||
""" gather image information. """
|
"""Gather image information."""
|
||||||
self.valid = False
|
self.valid = False
|
||||||
self.reset()
|
self.reset()
|
||||||
self.fullpath = fullpath
|
self.fullpath = fullpath
|
||||||
if path.isfile(self.fullpath) and access(self.fullpath, WRITEABLE):
|
if path.isfile(self.fullpath) and access(self.fullpath, W_OK):
|
||||||
self.filetype = path.splitext(self.fullpath)[1][1:]
|
self.filetype = path.splitext(self.fullpath)[1][1:]
|
||||||
if self.filetype == "jpg":
|
if self.filetype == "jpg":
|
||||||
self.filetype = "jpeg"
|
self.filetype = "jpeg"
|
||||||
|
|
@ -415,7 +405,7 @@ class Image:
|
||||||
self.recompression = False
|
self.recompression = False
|
||||||
|
|
||||||
def compress(self):
|
def compress(self):
|
||||||
""" Compress the image and return it to the thread. """
|
"""Compress the image and return it to the thread."""
|
||||||
if not self.valid:
|
if not self.valid:
|
||||||
raise "Tried to compress invalid image (unsupported format or not \
|
raise "Tried to compress invalid image (unsupported format or not \
|
||||||
file)"
|
file)"
|
||||||
|
|
@ -426,7 +416,7 @@ class Image:
|
||||||
"jpeg": "jpegoptim" + exe + " -f --strip-all '%(file)s'",
|
"jpeg": "jpegoptim" + exe + " -f --strip-all '%(file)s'",
|
||||||
"png": "optipng" + exe + " -force -o7 '%(file)s'&&advpng" + exe + " -z4 '%(file)s' && pngcrush -rem gAMA -rem alla -rem cHRM -rem iCCP -rem sRGB -rem time '%(file)s' '%(file)s.bak' && mv '%(file)s.bak' '%(file)s'"
|
"png": "optipng" + exe + " -force -o7 '%(file)s'&&advpng" + exe + " -z4 '%(file)s' && pngcrush -rem gAMA -rem alla -rem cHRM -rem iCCP -rem sRGB -rem time '%(file)s' '%(file)s.bak' && mv '%(file)s.bak' '%(file)s'"
|
||||||
}
|
}
|
||||||
# Create a backup file
|
# create a backup file
|
||||||
copy(self.fullpath, self.fullpath + '~')
|
copy(self.fullpath, self.fullpath + '~')
|
||||||
try:
|
try:
|
||||||
retcode = call(runString[self.filetype] % {"file": self.fullpath},
|
retcode = call(runString[self.filetype] % {"file": self.fullpath},
|
||||||
|
|
@ -437,12 +427,12 @@ class Image:
|
||||||
self.newfilesize = QFile(self.fullpath).size()
|
self.newfilesize = QFile(self.fullpath).size()
|
||||||
self.compressed = True
|
self.compressed = True
|
||||||
|
|
||||||
# Checks the new file and copy the backup
|
# checks the new file and copy the backup
|
||||||
if self.newfilesize >= self.oldfilesize:
|
if self.newfilesize >= self.oldfilesize:
|
||||||
copy(self.fullpath + '~', self.fullpath)
|
copy(self.fullpath + '~', self.fullpath)
|
||||||
self.newfilesize = self.oldfilesize
|
self.newfilesize = self.oldfilesize
|
||||||
|
|
||||||
# Removes the backup file
|
# removes the backup file
|
||||||
remove(self.fullpath + '~')
|
remove(self.fullpath + '~')
|
||||||
else:
|
else:
|
||||||
self.failed = True
|
self.failed = True
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,11 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
from os import path
|
||||||
|
|
||||||
from PyQt5.QtCore import *
|
from PyQt5.QtCore import *
|
||||||
from PyQt5.QtGui import *
|
from PyQt5.QtGui import *
|
||||||
from PyQt5.QtWidgets import *
|
from PyQt5.QtWidgets import *
|
||||||
from os import path
|
|
||||||
|
|
||||||
class TrimageTableView(QTableView):
|
class TrimageTableView(QTableView):
|
||||||
|
|
||||||
|
|
@ -34,12 +36,12 @@ class TrimageTableView(QTableView):
|
||||||
|
|
||||||
class Ui_trimage():
|
class Ui_trimage():
|
||||||
def get_image(self, image):
|
def get_image(self, image):
|
||||||
""" Get the correct link to the images used in the UI """
|
"""Get the correct link to the images used in the UI."""
|
||||||
imagelink = path.join(path.dirname(path.dirname(path.realpath(__file__))), "trimage/" + image)
|
imagelink = path.join(path.dirname(path.dirname(path.realpath(__file__))), "trimage/" + image)
|
||||||
return imagelink
|
return imagelink
|
||||||
|
|
||||||
def setupUi(self, trimage):
|
def setupUi(self, trimage):
|
||||||
""" Setup the entire UI """
|
"""Setup the entire UI."""
|
||||||
trimage.setObjectName("trimage")
|
trimage.setObjectName("trimage")
|
||||||
trimage.resize(600, 170)
|
trimage.resize(600, 170)
|
||||||
|
|
||||||
|
|
@ -147,7 +149,7 @@ class Ui_trimage():
|
||||||
QMetaObject.connectSlotsByName(trimage)
|
QMetaObject.connectSlotsByName(trimage)
|
||||||
|
|
||||||
def retranslateUi(self, trimage):
|
def retranslateUi(self, trimage):
|
||||||
""" Fill in the texts for all UI elements """
|
"""Fill in the texts for all UI elements."""
|
||||||
trimage.setWindowTitle(QApplication.translate("trimage",
|
trimage.setWindowTitle(QApplication.translate("trimage",
|
||||||
"Trimage image compressor", None))
|
"Trimage image compressor", None))
|
||||||
self.addfiles.setToolTip(QApplication.translate("trimage",
|
self.addfiles.setToolTip(QApplication.translate("trimage",
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue