Merge pull request #47 from Huluti/master

First try to adopt Python3 and PyQt5
This commit is contained in:
Kilian Valkhof 2019-02-21 10:41:35 +01:00 committed by GitHub
commit 117a1a36cc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 313 additions and 449 deletions

119
.gitignore vendored
View file

@ -1,5 +1,116 @@
*.pyc
MANIFEST
dist/
build/
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
pip-wheel-metadata/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
.hypothesis/
.pytest_cache/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
.python-version
# celery beat schedule file
celerybeat-schedule
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/

View file

@ -1,4 +1,3 @@
include COPYING MANIFEST MANIFEST.in README trimage
include COPYING MANIFEST MANIFEST.in README.md trimage
recursive-include desktop *.svg *.desktop
recursive-include src/ *.py *.png

15
README
View file

@ -1,15 +0,0 @@
Trimage image compressor
A cross-platform tool for optimizing PNG and JPG files.
Trimage is a cross-platform GUI and command-line interface to optimize image
files via "optipng":http://optipng.sourceforge.net/,
"advpng":http://advancemame.sourceforge.net/comp-readme.html and
"jpegoptim":http://www.kokkonen.net/tjko/projects.html, depending on the
filetype (currently, PNG and JPG files are supported). It was inspired by
"imageoptim":http://imageoptim.pornel.net/. All image files are losslessly
compressed on the highest available compression levels. Trimage gives you
various input functions to fit your own workflow: A regular file dialog,
dragging and dropping and various command line options.
Visit "Trimage.org":http://trimage.org for more information

21
README.md Normal file
View file

@ -0,0 +1,21 @@
# Trimage image compressor
A cross-platform tool for optimizing PNG and JPG files.
Trimage is a cross-platform GUI and command-line interface to optimize image files via [advpng](http://advancemame.sourceforge.net/comp-readme.html), [jpegoptim](http://www.kokkonen.net/tjko/projects.html), [optipng](http://optipng.sourceforge.net) and [pngcrush](https://pmt.sourceforge.io/pngcrush) depending on the
filetype (currently, PNG and JPG files are supported).
It was inspired by
[imageoptim](http://imageoptim.pornel.net).
All image files are losslessly
compressed on the highest available compression levels. Trimage gives you
various input functions to fit your own workflow: a regular file dialog,
dragging and dropping and various command line options.
Visit [Trimage.org](http://trimage.org) for more information.
## Prerequisites
- advpng
- jpegoptim
- optipng
- pngcrush

17
TODO.md Normal file
View file

@ -0,0 +1,17 @@
# Todo
- general refactoring
- sys.exit(1) for errors -- how to handle? Not good to simply sys.exit() from any random part of code (can leave things in a mess)
- consider context managers for handling compression, so as to keep operations atomic and/or rollback-able
- add a recursive option on the command-line for use with -d
- make -f accept a list of files
- make the current verbose be "normal", and make -verbose print the commandline app prints as well
- find a way to specify the version once for everywhere
- notification area drag/drop widget -> probably need gtk for gnome
- figure out how to make mac and win versions (someone else :) <- via gui2exe
- animate compressing.gif
- allow selection/deletion of rows from table (and subsequently the imagelist)
- punypng api? http://www.gracepointafterfive.com/punypng/api
- imagemagick/graphicsmagick?
- always on top option
- intelligently recompress, i.e. go through the list of files, recompress each until no more gains are seen (and a sensible number-of-tries limit isn't exceeded), and flag that file as fully-optimised. Repeat for each file in the list, until all are done. Saves pointlessly trying to optimise files. Consider the case of a directory of 100 files, already optimised once. Recompressing maximally compresses 90. Recompressing again would currently try to recompress all 100, when only 10 would be worthy of trying to compress further

5
debian/control vendored
View file

@ -3,13 +3,13 @@ Section: graphics
Priority: optional
Maintainer: Kilian Valkhof <kilian@kilianvalkhof.com>
Build-Depends: debhelper (>=7), python-support (>=0.8.7), python
XS-Python-Version: >=2.6
XS-Python-Version: >=3.4
Standards-Version: 3.9.1
Homepage: http://trimage.org
Package: trimage
Architecture: all
Depends: ${misc:Depends}, ${python:Depends}, python-qt4 (>=4.4), optipng (>=0.6.2.1), advancecomp (>=1.15), jpegoptim (>=1.2.2), pngcrush (>=1.6.7)
Depends: ${misc:Depends}, ${python:Depends}, python-pyqt5 (>=5.7), optipng (>=0.6.2.1), advancecomp (>=1.15), jpegoptim (>=1.2.2), pngcrush (>=1.6.7)
XB-Python-Version: ${python:Versions}
Description: GUI and command-line interface to optimize image files
Trimage is a cross-platform GUI and command-line interface to optimize image
@ -18,4 +18,3 @@ Description: GUI and command-line interface to optimize image files
compressed on the highest available compression levels. Trimage gives you
various input functions to fit your own workflow: A regular file dialog,
dragging and dropping and various command line options.

View file

@ -1,37 +0,0 @@
==========================================
todo app wise
- general refactoring
- sys.exit(1) for errors -- how to handle? Not good to simply sys.exit() from
any random part of code (can leave things in a mess)
- consider context managers for handling compression, so as to keep operations
atomic and/or rollback-able
- add a recursive option on the command-line for use with -d
- make -f accept a list of files
- make the current verbose be "normal", and make -verbose print the commandline
app prints as well
- find a way to specify the version once for everywhere
- notification area drag/drop widget
-> probably need gtk for gnome
todo else
- figure out how to make mac and win versions (someone else :) <- via gui2exe
===========================================
later versions:
animate compressing.gif
allow selection/deletion of rows from table (and subsequently the imagelist)
punypng api? http://www.gracepointafterfive.com/punypng/api
imagemagick/graphicsmagick?
always on top option
intelligently recompress, i.e. go through the list of files, recompress
each until no more gains are seen (and a sensible number-of-tries limit
isn't exceeded), and flag that file as fully-optimised. Repeat for each
file in the list, until all are done. Saves pointlessly trying to
optimise files. Consider the case of a directory of 100 files, already
optimised once. Recompressing maximally compresses 90. Recompressing
again would currently try to recompress all 100, when only 10 would be
worthy of trying to compress further.

View file

@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
import sys
win=(sys.platform == "win32")
@ -9,7 +9,7 @@ if win:
from distutils.core import setup
setup(name = "trimage",
version = "1.0.2",
version = "1.0.5",
description = "Trimage image compressor - A cross-platform tool for optimizing PNG and JPG files",
author = "Kilian Valkhof, Paul Chaplin",
author_email = "help@trimage.org",
@ -17,15 +17,14 @@ setup(name = "trimage",
license = "MIT license",
package_dir = {'trimage' : 'src/trimage'},
packages = ["trimage",
"trimage.filesize",
"trimage.ThreadPool",],
"trimage.ThreadPool"],
package_data = {"trimage" : ["pixmaps/*.*"] },
data_files=[('share/icons/hicolor/scalable/apps', ['desktop/trimage.svg']),
('share/applications', ['desktop/trimage.desktop']),
('share/man/man1', ['doc/trimage.1'])],
scripts = ["trimage"],
long_description = """Trimage is a cross-platform GUI and command-line interface to optimize image files via optipng, advpng and jpegoptim, depending on the filetype (currently, PNG and JPG files are supported). It was inspired by imageoptim. All image files are losslessy compressed on the highest available compression levels. Trimage gives you various input functions to fit your own workflow: A regular file dialog, dragging and dropping and various command line options.""",
requires = ["PyQt4 (>=4.4)"],
requires = ["PyQt5"],
#for py2exe
windows=[r'src\trimage\trimage.py'],

View file

@ -1,3 +1,5 @@
#!/usr/bin/env python3
'''
ThreadPool Implementation
@ -8,7 +10,7 @@ ThreadPool Implementation
from __future__ import with_statement
from threading import Thread, RLock
from time import sleep
from Queue import Queue, Empty
from queue import Queue, Empty
import logging
import sys
@ -86,7 +88,7 @@ class ThreadPool:
'''
try:
return_value = self.callable(*self.arguments) #IGNORE:W0142
except Exception, excep: #IGNORE:W0703
except Exception as excep: #IGNORE:W0703
logger = logging.getLogger("threadpool.worker")
logger.warning("A job in the ThreadPool raised an exception: " + excep)
#else do nothing cause we don't know what to do...
@ -95,7 +97,7 @@ class ThreadPool:
try:
if (self.return_callback != None):
self.return_callback(return_value)
except Exception, _: #IGNORE:W0703 everything could go wrong...
except Exception as _: #IGNORE:W0703 everything could go wrong...
logger = logging.getLogger('threadpool')
logger.warning('Error while delivering return value to callback function')

View file

@ -1 +1 @@
from ThreadPool import ThreadPool, ThreadPoolMixIn
from .ThreadPool import ThreadPool, ThreadPoolMixIn

View file

@ -1,71 +0,0 @@
Metadata-Version: 1.0
Name: hurry.filesize
Version: 0.9
Summary: A simple Python library for human readable file sizes (or anything sized in bytes).
Home-page: UNKNOWN
Author: Martijn Faassen, Startifact
Author-email: faassen@startifact.com
License: ZPL 2.1
Description: hurry.filesize
==============
hurry.filesize a simple Python library that can take a number of bytes and
returns a human-readable string with the size in it, in kilobytes (K),
megabytes (M), etc.
The default system it uses is "traditional", where multipliers of 1024
increase the unit size::
>>> from hurry.filesize import size
>>> size(1024)
'1K'
An alternative, slightly more verbose system::
>>> from hurry.filesize import alternative
>>> size(1, system=alternative)
'1 byte'
>>> size(10, system=alternative)
'10 bytes'
>>> size(1024, system=alternative)
'1 KB'
A verbose system::
>>> from hurry.filesize import verbose
>>> size(10, system=verbose)
'10 bytes'
>>> size(1024, system=verbose)
'1 kilobyte'
>>> size(2000, system=verbose)
'1 kilobyte'
>>> size(3000, system=verbose)
'2 kilobytes'
>>> size(1024 * 1024, system=verbose)
'1 megabyte'
>>> size(1024 * 1024 * 3, system=verbose)
'3 megabytes'
You can also use the SI system, where multipliers of 1000 increase the unit
size::
>>> from hurry.filesize import si
>>> size(1000, system=si)
'1K'
Changes
=======
0.9 (2009-03-11)
----------------
* Initial public release.
Download
========
Keywords: file size bytes
Platform: UNKNOWN
Classifier: Programming Language :: Python
Classifier: Topic :: Software Development :: Libraries :: Python Modules

View file

@ -1,50 +0,0 @@
hurry.filesize
==============
hurry.filesize a simple Python library that can take a number of bytes and
returns a human-readable string with the size in it, in kilobytes (K),
megabytes (M), etc.
The default system it uses is "traditional", where multipliers of 1024
increase the unit size::
>>> from hurry.filesize import size
>>> size(1024)
'1K'
An alternative, slightly more verbose system::
>>> from hurry.filesize import alternative
>>> size(1, system=alternative)
'1 byte'
>>> size(10, system=alternative)
'10 bytes'
>>> size(1024, system=alternative)
'1 KB'
A verbose system::
>>> from hurry.filesize import verbose
>>> size(10, system=verbose)
'10 bytes'
>>> size(1024, system=verbose)
'1 kilobyte'
>>> size(2000, system=verbose)
'1 kilobyte'
>>> size(3000, system=verbose)
'2 kilobytes'
>>> size(1024 * 1024, system=verbose)
'1 megabyte'
>>> size(1024 * 1024 * 3, system=verbose)
'3 megabytes'
You can also use the SI system, where multipliers of 1000 increase the unit
size::
>>> from hurry.filesize import si
>>> size(1000, system=si)
'1K'
http://pypi.python.org/pypi/hurry.filesize

View file

@ -1,2 +0,0 @@
from filesize import size
from filesize import traditional, alternative, verbose, iec, si

View file

@ -1,115 +0,0 @@
'''
hurry.filesize
@author: Martijn Faassen, Startifact
@license: ZPL 2.1
'''
traditional = [
(1024 ** 5, 'P'),
(1024 ** 4, 'T'),
(1024 ** 3, 'G'),
(1024 ** 2, 'M'),
(1024 ** 1, 'K'),
(1024 ** 0, 'B'),
]
alternative = [
(1024 ** 5, ' PB'),
(1024 ** 4, ' TB'),
(1024 ** 3, ' GB'),
(1024 ** 2, ' MB'),
(1024 ** 1, ' KB'),
(1024 ** 0, (' byte', ' bytes')),
]
verbose = [
(1024 ** 5, (' petabyte', ' petabytes')),
(1024 ** 4, (' terabyte', ' terabytes')),
(1024 ** 3, (' gigabyte', ' gigabytes')),
(1024 ** 2, (' megabyte', ' megabytes')),
(1024 ** 1, (' kilobyte', ' kilobytes')),
(1024 ** 0, (' byte', ' bytes')),
]
iec = [
(1024 ** 5, 'Pi'),
(1024 ** 4, 'Ti'),
(1024 ** 3, 'Gi'),
(1024 ** 2, 'Mi'),
(1024 ** 1, 'Ki'),
(1024 ** 0, ''),
]
si = [
(1000 ** 5, 'P'),
(1000 ** 4, 'T'),
(1000 ** 3, 'G'),
(1000 ** 2, 'M'),
(1000 ** 1, 'K'),
(1000 ** 0, 'B'),
]
def size(bytes, system=traditional):
"""Human-readable file size.
Using the traditional system, where a factor of 1024 is used::
>>> size(10)
'10B'
>>> size(100)
'100B'
>>> size(1000)
'1000B'
>>> size(2000)
'1K'
>>> size(10000)
'9K'
>>> size(20000)
'19K'
>>> size(100000)
'97K'
>>> size(200000)
'195K'
>>> size(1000000)
'976K'
>>> size(2000000)
'1M'
Using the SI system, with a factor 1000::
>>> size(10, system=si)
'10B'
>>> size(100, system=si)
'100B'
>>> size(1000, system=si)
'1K'
>>> size(2000, system=si)
'2K'
>>> size(10000, system=si)
'10K'
>>> size(20000, system=si)
'20K'
>>> size(100000, system=si)
'100K'
>>> size(200000, system=si)
'200K'
>>> size(1000000, system=si)
'1M'
>>> size(2000000, system=si)
'2M'
"""
for factor, suffix in system:
if bytes >= factor:
break
amount = int(bytes/factor)
if isinstance(suffix, tuple):
singular, multiple = suffix
if amount == 1:
suffix = singular
else:
suffix = multiple
return str(amount) + suffix

9
src/trimage/tools.py Normal file
View file

@ -0,0 +1,9 @@
#!/usr/bin/env python3
def human_readable_size(num, suffix='B'):
for unit in ['','K','M','G','T','P','E','Z']:
if abs(num) < 1024.0:
return "%3.1f%s%s" % (num, unit, suffix)
num /= 1024.0
return "%.1f%s%s" % (num, 'Y', suffix)

View file

@ -1,4 +1,5 @@
#!/usr/bin/python
#!/usr/bin/env python3
import time
import sys
import errno
@ -11,12 +12,12 @@ from shutil import copy
from subprocess import call, PIPE
from optparse import OptionParser
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from filesize import *
from imghdr import what as determinetype
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from Queue import Queue
from tools import human_readable_size
from queue import Queue
from ThreadPool import ThreadPool
from multiprocessing import cpu_count
@ -25,7 +26,7 @@ from ui import Ui_trimage
VERSION = "1.0.5"
class StartQT4(QMainWindow):
class StartQT5(QMainWindow):
def __init__(self, parent=None):
QWidget.__init__(self, parent)
@ -40,7 +41,8 @@ class StartQT4(QMainWindow):
QCoreApplication.setOrganizationDomain("trimage.org")
QCoreApplication.setApplicationName("Trimage")
self.settings = QSettings()
self.restoreGeometry(self.settings.value("geometry").toByteArray())
if self.settings.value("geometry"):
self.restoreGeometry(self.settings.value("geometry"))
# check if apps are installed
if self.checkapps():
@ -61,17 +63,12 @@ class StartQT4(QMainWindow):
self.thread = Worker()
# connect signals with slots
QObject.connect(self.ui.addfiles, SIGNAL("clicked()"),
self.file_dialog)
QObject.connect(self.ui.recompress, SIGNAL("clicked()"),
self.recompress_files)
QObject.connect(self.quit_shortcut, SIGNAL("activated()"),
qApp, SLOT('quit()'))
QObject.connect(self.ui.processedfiles, SIGNAL("fileDropEvent"),
self.file_drop)
QObject.connect(self.thread, SIGNAL("finished()"), self.update_table)
QObject.connect(self.thread, SIGNAL("terminated()"), self.update_table)
QObject.connect(self.thread, SIGNAL("updateUi"), self.update_table)
self.ui.addfiles.clicked.connect(self.file_dialog)
self.ui.recompress.clicked.connect(self.recompress_files)
self.quit_shortcut.activated.connect(self.close)
self.ui.processedfiles.drop_event_signal.connect(self.file_drop)
self.thread.finished.connect(self.update_table)
self.thread.update_ui_signal.connect(self.update_table)
self.compressing_icon = QIcon(QPixmap(self.ui.get_image("pixmaps/compressing.gif")))
@ -103,14 +100,14 @@ class StartQT4(QMainWindow):
# make sure we quit after processing finished if using cli
if options.filename or options.directory:
QObject.connect(self.thread, SIGNAL("finished()"), quit)
self.thread.finished.connect(quit)
self.cli = True
# send to correct function
if options.filename:
self.file_from_cmd(options.filename.decode("utf-8"))
self.file_from_cmd(options.filename)
if options.directory:
self.dir_from_cmd(options.directory.decode("utf-8"))
self.dir_from_cmd(options.directory)
self.verbose = options.verbose
@ -143,8 +140,9 @@ class StartQT4(QMainWindow):
def file_dialog(self):
"""Open a file dialog and send the selected images to compress_file."""
fd = QFileDialog(self)
fd.restoreState(self.settings.value("fdstate").toByteArray())
directory = self.settings.value("directory", QVariant("")).toString()
if (self.settings.value("fdstate")):
fd.restoreState(self.settings.value("fdstate"))
directory = self.settings.value("directory", QVariant(""))
fd.setDirectory(directory)
images = fd.getOpenFileNames(self,
@ -154,9 +152,10 @@ class StartQT4(QMainWindow):
"Image files (*.png *.jpg *.jpeg *.PNG *.JPG *.JPEG)")
self.settings.setValue("fdstate", QVariant(fd.saveState()))
images = images[0]
if images:
self.settings.setValue("directory", QVariant(path.dirname(unicode(images[0]))))
self.delegator([unicode(fullpath) for fullpath in images])
self.settings.setValue("directory", QVariant(path.dirname(images[0])))
self.delegator([fullpath for fullpath in images])
def recompress_files(self):
"""Send each file in the current file list to compress_file again."""
@ -173,15 +172,15 @@ class StartQT4(QMainWindow):
delegatorlist = []
for fullpath in images:
try: # recompress images already in the list
image = (i.image for i in self.imagelist
if i.image.fullpath == fullpath).next()
image = next(i.image for i in self.imagelist
if i.image.fullpath == fullpath)
if image.compressed:
image.reset()
image.recompression = True
delegatorlist.append(image)
except StopIteration:
if not path.isdir(fullpath):
self. add_image(fullpath, delegatorlist)
if not path.isdir(fullpath):
self.add_image(fullpath, delegatorlist)
else:
self.walk(fullpath, delegatorlist)
@ -214,7 +213,7 @@ class StartQT4(QMainWindow):
self.systemtray.trayIcon.setToolTip("Trimage image compressor (" + str(len(self.imagelist)) + " files)")
self.setWindowTitle("Trimage image compressor (" + str(len(self.imagelist)) + " files)")
else:
print >> sys.stderr, u"[error] %s not a supported image file and/or not writeable" % image.fullpath
print("[error] {} not a supported image file and/or not writable".format(image.fullpath), file=sys.stderr)
"""
UI Functions
@ -264,22 +263,22 @@ class StartQT4(QMainWindow):
retcode = self.safe_call("jpegoptim" + exe + " --version")
if retcode != 0:
status = True
sys.stderr.write("[error] please install jpegoptim")
print("[error] please install jpegoptim", file=sys.stderr)
retcode = self.safe_call("optipng" + exe + " -v")
if retcode != 0:
status = True
sys.stderr.write("[error] please install optipng")
print("[error] please install optipng", file=sys.stderr)
retcode = self.safe_call("advpng" + exe + " --version")
if retcode != 0:
status = True
sys.stderr.write("[error] please install advancecomp")
print("[error] please install advancecomp", file=sys.stderr)
retcode = self.safe_call("pngcrush" + exe + " -version")
if retcode != 0:
status = True
sys.stderr.write("[error] please install pngcrush")
print("[error] please install pngcrush", file=sys.stderr)
return status
def safe_call(self, command):
@ -287,7 +286,7 @@ class StartQT4(QMainWindow):
while True:
try:
return call(command, shell=True, stdout=PIPE)
except OSError, e:
except OSError as e:
if e.errno == errno.EINTR:
continue
else:
@ -357,9 +356,9 @@ class ImageRow:
self.image = image
d = {
'shortname': lambda i: self.statusStr() % i.shortname,
'oldfilesizestr': lambda i: size(i.oldfilesize, system=alternative)
'oldfilesizestr': lambda i: human_readable_size(i.oldfilesize)
if i.compressed else "",
'newfilesizestr': lambda i: size(i.newfilesize, system=alternative)
'newfilesizestr': lambda i: human_readable_size(i.newfilesize)
if i.compressed else "",
'ratiostr': lambda i:
"%.1f%%" % (100 - (float(i.newfilesize) / i.oldfilesize * 100))
@ -399,7 +398,9 @@ class Image:
self.reset()
self.fullpath = fullpath
if path.isfile(self.fullpath) and access(self.fullpath, WRITEABLE):
self.filetype = determinetype(self.fullpath)
self.filetype = path.splitext(self.fullpath)[1][1:]
if self.filetype == "jpg":
self.filetype = "jpeg"
if self.filetype in ["jpeg", "png"]:
oldfile = QFileInfo(self.fullpath)
self.shortname = oldfile.fileName()
@ -407,15 +408,6 @@ class Image:
self.icon = QIcon(self.fullpath)
self.valid = True
#def _determinetype(self):
# """ Determine the filetype of the file using imghdr. """
# filetype = determinetype(self.fullpath)
# if filetype in ["jpeg", "png"]:
# self.filetype = filetype
# else:
# self.filetype = None
# return self.filetype
def reset(self):
self.failed = False
self.compressed = False
@ -431,8 +423,8 @@ class Image:
self.compressing = True
exe = ".exe" if (sys.platform == "win32") else ""
runString = {
"jpeg": u"jpegoptim" + exe + " -f --strip-all '%(file)s'",
"png": u"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'"
"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'"
}
# Create a backup file
copy(self.fullpath, self.fullpath + '~')
@ -461,6 +453,8 @@ class Image:
class Worker(QThread):
update_ui_signal = pyqtSignal()
def __init__(self, parent=None):
QThread.__init__(self, parent)
self.toDisplay = Queue()
@ -488,7 +482,7 @@ class Worker(QThread):
tp._ThreadPool__jobs.empty()):
image = self.toDisplay.get()
self.emit(SIGNAL("updateUi"))
self.update_ui_signal.emit()
if not self.showapp and self.verbose: # we work via the commandline
if image.retcode == 0:
@ -497,7 +491,7 @@ class Worker(QThread):
+ ir['oldfilesizestr'] + ", New Size: "
+ ir['newfilesizestr'] + ", Ratio: " + ir['ratiostr'])
else:
print >> sys.stderr, u"[error] %s could not be compressed" % image.fullpath
print("[error] {} could not be compressed".format(image.fullpath), file=sys.stderr)
class Systray(QWidget):
@ -511,15 +505,14 @@ class Systray(QWidget):
def createActions(self):
self.quitAction = QAction(self.tr("&Quit"), self)
QObject.connect(self.quitAction, SIGNAL("triggered()"),
qApp, SLOT("quit()"))
self.quitAction.triggered.connect(self.parent.close)
self.addFiles = QAction(self.tr("&Add and compress"), self)
icon = QIcon()
icon.addPixmap(QPixmap(self.parent.ui.get_image(("pixmaps/list-add.png"))),
QIcon.Normal, QIcon.Off)
self.addFiles.setIcon(icon)
QObject.connect(self.addFiles, SIGNAL("triggered()"), self.parent.file_dialog)
self.addFiles.triggered.connect(self.parent.file_dialog)
self.recompress = QAction(self.tr("&Recompress"), self)
icon2 = QIcon()
@ -527,10 +520,11 @@ class Systray(QWidget):
QIcon.Normal, QIcon.Off)
self.recompress.setIcon(icon2)
self.recompress.setDisabled(True)
QObject.connect(self.addFiles, SIGNAL("triggered()"), self.parent.recompress_files)
self.addFiles.triggered.connect(self.parent.recompress_files)
self.hideMain = QAction(self.tr("&Hide window"), self)
QObject.connect(self.hideMain, SIGNAL("triggered()"), self.parent.hide_main_window)
self.hideMain.triggered.connect(self.parent.hide_main_window)
def createTrayIcon(self):
self.trayIconMenu = QMenu(self)
@ -550,7 +544,7 @@ class Systray(QWidget):
if __name__ == "__main__":
app = QApplication(sys.argv)
myapp = StartQT4()
myapp = StartQT5()
if myapp.showapp:
myapp.show()

View file

@ -1,8 +1,14 @@
from PyQt4.QtCore import *
from PyQt4.QtGui import *
#!/usr/bin/env python3
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from os import path
class TrimageTableView(QTableView):
drop_event_signal = pyqtSignal(list)
"""Init the table drop event."""
def __init__(self, parent=None):
super(TrimageTableView, self).__init__(parent)
@ -21,12 +27,12 @@ class TrimageTableView(QTableView):
event.accept()
filelist = []
for url in event.mimeData().urls():
filelist.append(unicode(url.toLocalFile()))
filelist.append(url.toLocalFile())
self.emit(SIGNAL("fileDropEvent"), (filelist))
self.drop_event_signal.emit(filelist)
class Ui_trimage(object):
class Ui_trimage():
def get_image(self, image):
""" Get the correct link to the images used in the UI """
imagelink = path.join(path.dirname(path.dirname(path.realpath(__file__))), "trimage/" + image)
@ -44,7 +50,7 @@ class Ui_trimage(object):
self.centralwidget.setObjectName("centralwidget")
self.gridLayout_2 = QGridLayout(self.centralwidget)
self.gridLayout_2.setMargin(0)
self.gridLayout_2.setContentsMargins(0, 0, 0, 0)
self.gridLayout_2.setSpacing(0)
self.gridLayout_2.setObjectName("gridLayout_2")
@ -60,7 +66,7 @@ class Ui_trimage(object):
self.verticalLayout = QVBoxLayout(self.widget)
self.verticalLayout.setSpacing(0)
self.verticalLayout.setMargin(0)
self.verticalLayout.setContentsMargins(0, 0, 0, 0)
self.verticalLayout.setObjectName("verticalLayout")
self.frame = QFrame(self.widget)
@ -68,12 +74,12 @@ class Ui_trimage(object):
self.verticalLayout_2 = QVBoxLayout(self.frame)
self.verticalLayout_2.setSpacing(0)
self.verticalLayout_2.setMargin(0)
self.verticalLayout_2.setContentsMargins(0, 0, 0, 0)
self.verticalLayout_2.setObjectName("verticalLayout_2")
self.horizontalLayout = QHBoxLayout()
self.horizontalLayout.setSpacing(0)
self.horizontalLayout.setMargin(10)
self.horizontalLayout.setContentsMargins(10, 10, 10, 10)
self.horizontalLayout.setObjectName("horizontalLayout")
self.addfiles = QPushButton(self.frame)
@ -93,7 +99,7 @@ class Ui_trimage(object):
font.setPointSize(8)
self.label.setFont(font)
self.label.setFrameShadow(QFrame.Plain)
self.label.setMargin(1)
self.label.setContentsMargins(1, 1, 1, 1)
self.label.setIndent(10)
self.label.setObjectName("label")
self.horizontalLayout.addWidget(self.label)
@ -143,24 +149,22 @@ class Ui_trimage(object):
def retranslateUi(self, trimage):
""" Fill in the texts for all UI elements """
trimage.setWindowTitle(QApplication.translate("trimage",
"Trimage image compressor", None, QApplication.UnicodeUTF8))
"Trimage image compressor", None))
self.addfiles.setToolTip(QApplication.translate("trimage",
"Add file to the compression list", None,
QApplication.UnicodeUTF8))
"Add file to the compression list", None))
self.addfiles.setText(QApplication.translate("trimage",
"&Add and compress", None, QApplication.UnicodeUTF8))
"&Add and compress", None))
self.addfiles.setShortcut(QApplication.translate("trimage",
"Alt+A", None, QApplication.UnicodeUTF8))
"Alt+A", None))
self.label.setText(QApplication.translate("trimage",
"Drag and drop images onto the table", None,
QApplication.UnicodeUTF8))
"Drag and drop images onto the table", None))
self.recompress.setToolTip(QApplication.translate("trimage",
"Recompress all images", None, QApplication.UnicodeUTF8))
"Recompress all images", None))
self.recompress.setText(QApplication.translate("trimage",
"&Recompress", None, QApplication.UnicodeUTF8))
"&Recompress", None))
self.recompress.setShortcut(QApplication.translate("trimage",
"Alt+R", None, QApplication.UnicodeUTF8))
"Alt+R", None))
self.processedfiles.setToolTip(QApplication.translate("trimage",
"Drag files in here", None, QApplication.UnicodeUTF8))
"Drag files in here", None))
self.processedfiles.setWhatsThis(QApplication.translate("trimage",
"Drag files in here", None, QApplication.UnicodeUTF8))
"Drag files in here", None))

View file

@ -1,5 +1,4 @@
#!/usr/bin/env python
#coding: utf-8
#!/usr/bin/env python3
#
#Copyright (c) 2010 Kilian Valkhof, Paul Chaplin, Tarnay Kálmán
#