Compare commits

...

76 commits

Author SHA1 Message Date
Kilian Valkhof
ad74684272
Merge pull request #83 from Mte90/patch-2
Fix incomplete code of #77
2021-03-10 14:41:44 +01:00
Daniele Scasciafratte
031adf6054
Fix incomplete code of #77
I forgot to change the various `%s` in the pull request with the rest of the function or it will be print "Compressing %s".
2021-03-10 12:58:46 +01:00
Kilian Valkhof
f35be9c750
Merge pull request #82 from Mte90/patch-1
Fix #77
2021-03-08 14:03:34 +01:00
Daniele Scasciafratte
636b5a9750
Fix #77
This fix https://github.com/Kilian/Trimage/issues/77
As debian user this fix the issue for me
2021-03-04 19:26:55 +01:00
Kilian Valkhof
c21089f97b
Merge pull request #74 from carsonreinke/fix-typeerror
Missing format specifier for arguments of image status
2020-09-30 13:21:24 +02:00
Kilian Valkhof
f37c8b6ffc
Merge pull request #76 from featherbear/master
Remove unreachable shutdown code
2020-09-30 13:19:37 +02:00
Andrew Wong
8af532f25e Remove unreachable shutdown code
* Implementing `__del__` is discouraged
  * Imports (i.e. `import logging`) are cleaned up, leading to NoneType related errors
* When running via GUI mode, the shutdown code is never reached; we can let Python's internal GC clean everything
2020-09-30 19:22:46 +10:00
Carson Reinke
493a0e18d2 Missing format specifier for arguments of image status
Fixes https://github.com/Kilian/Trimage/issues/73
2020-06-23 15:30:34 -04:00
Kilian Valkhof
224f6b3503
Merge pull request #71 from kalmi/macos
Add macOS instructions to website
2020-04-24 09:35:43 +02:00
Kálmán Tarnay
c3244e19a6 add macos instructions to website 2020-04-23 17:44:12 +02:00
Kilian Valkhof
269e052ba4
Update README.md 2019-12-20 16:51:10 +01:00
Kilian Valkhof
49272e0d95
Merge pull request #66 from hosiet/patch-1
Fix trimage.desktop grammar
2019-12-04 09:52:17 +01:00
Boyuan Yang
1342503b54
Fix trimage.desktop grammar
According to https://specifications.freedesktop.org/desktop-entry-spec/latest/ar01s04.html , Keywords should be split by semicolons, not commas.
2019-12-03 17:00:44 -05:00
Kilian Valkhof
0cbbfcdfe8
Merge pull request #64 from Huluti/remove-win32-support
Remove win32 bytes following d6118b5
2019-10-14 17:00:36 +02:00
Hugo Posnic
9d6edd3847 Remove win32 bytes following d6118b5 2019-10-03 17:05:33 +02:00
kilian
9bdd44a4e4 further refinement/updates of debian folder 2019-03-12 12:36:32 +01:00
kilian
8376c4a238 update version number to 1.0.6 in various places 2019-03-12 12:15:49 +01:00
kilian
54d4b74172 update debian folder 2019-03-12 12:03:15 +01:00
kilian
e3b5146977 update website 2019-03-12 11:49:45 +01:00
Kilian Valkhof
f2ff0448c4
Merge pull request #57 from Huluti/master
Fix #28 + Little changes to setup.py
2019-03-12 11:42:21 +01:00
Huluti
5f5757f575 Fix #28 2019-03-07 16:45:55 +01:00
Huluti
a3f417c43e setup.py: add a missing dependency in the long description 2019-03-07 16:10:19 +01:00
Huluti
d6118b520b Remove Windows options from setup.py 2019-03-07 16:09:21 +01:00
Huluti
f5ff57ff48 Just one return line fix 2019-03-07 15:59:05 +01:00
Kilian Valkhof
d8d207438e
Merge pull request #56 from Huluti/fix41
Fix #41
2019-03-05 09:19:00 +01:00
Huluti
27b22807bc Fix #41 2019-03-04 21:46:25 +01:00
Kilian Valkhof
891bc9b73f
Merge pull request #53 from Huluti/master
A fix and some cosmetic changes
2019-02-25 10:45:47 +01:00
Huluti
5553e7fabe Fix a bug introcuded in 13f43bf: allow extensions even in upper case 2019-02-23 20:58:02 +01:00
Huluti
9ea961e87c Remove some extra spaces 2019-02-23 20:54:27 +01:00
Huluti
c040b63595 Move two functions in the tools.py file 2019-02-23 20:48:49 +01:00
Huluti
b829b6ac5f Minor cosmetics 2019-02-22 21:23:37 +01:00
Kilian Valkhof
be7fe35ba9
Merge pull request #52 from Huluti/cleaning
Just some cleaning
2019-02-22 10:03:00 +01:00
Hugo Posnic
915a360a09 Uniformize comments and docstrings syntax 2019-02-21 16:37:03 +01:00
Hugo Posnic
06aad62cb6 Simpler check of dependencies 2019-02-21 16:34:07 +01:00
Hugo Posnic
fa94b546fb Reorder imports (PEP-8) 2019-02-21 16:25:15 +01:00
Kilian Valkhof
1ecff8b3d9
Merge pull request #50 from Huluti/simplify-structure
Simplify the structure
2019-02-21 16:01:58 +01:00
Kilian Valkhof
9ee9548d47
Merge pull request #49 from Huluti/update-readme
Update README
2019-02-21 16:00:24 +01:00
Hugo Posnic
4e702d3f3a Simplify the structure 2019-02-21 15:34:59 +01:00
Hugo Posnic
006256e08b Update README 2019-02-21 15:26:20 +01:00
Kilian Valkhof
117a1a36cc
Merge pull request #47 from Huluti/master
First try to adopt Python3 and PyQt5
2019-02-21 10:41:35 +01:00
Hugo Posnic
1e602b2a77 Remove the need to use the hurry.filesize package 2019-02-20 17:10:03 +01:00
Hugo Posnic
460161b6ee Update generators 2019-02-20 16:30:20 +01:00
Hugo Posnic
030684fe60 Fix two little errors 2019-02-20 16:21:09 +01:00
Hugo Posnic
b2713d5485 Update gitignore 2019-02-20 16:11:49 +01:00
Hugo Posnic
95512644b6 Update README 2019-02-20 15:38:19 +01:00
Hugo Posnic
fb1c463a03 Fix filetype after last commit 2019-02-20 15:37:35 +01:00
Hugo Posnic
d2c0a7905b Add an other check to avoid an other TypeError 2019-02-20 15:28:09 +01:00
Hugo Posnic
13f43bfa2f Simplify way to check if an image is valid
determinetype functions has some defaults
2019-02-20 15:27:45 +01:00
Hugo Posnic
f7531a1095 Replace sys.stderr.write by prints 2019-02-20 15:16:28 +01:00
Hugo Posnic
02a92463e5 Test geometry setting to avoid a TypeError 2019-02-20 14:49:00 +01:00
Hugo Posnic
c38cf92f25 Fix imports 2018-04-09 19:19:41 +02:00
Hugo Posnic
26878908c0 Ue Python3 shebangs 2018-04-09 19:17:39 +02:00
Hugo Posnic
42008757f2 Redesign todo 2017-11-26 11:53:11 +01:00
Hugo Posnic
8e415cb451 Update debian control file to Python 3 and Qt5 2017-11-25 17:08:49 +01:00
Hugo Posnic
23c3243209 Remove two remaining "u" chars 2017-11-19 17:48:13 +01:00
Hugo Posnic
3a19f3cef8 Don't need "(object)" for classes in Python3 2017-11-18 20:18:48 +01:00
Hugo Posnic
59b3d8c94d Python 3 use utf8 by default 2017-11-18 18:05:28 +01:00
Hugo Posnic
573dcab3d2 Remove decode methods (Python 3 is utf8 by default) 2017-11-18 18:04:15 +01:00
Hugo Posnic
d7a0f84f64 Adopt the new signal system for remaining items 2017-11-18 17:10:23 +01:00
Hugo Posnic
797cc433b3 Readme file in markdown 2017-11-18 16:40:05 +01:00
Hugo Posnic
461ae9fd57 Reintroduce missing changes 2017-11-18 16:25:49 +01:00
Hugo Posnic
648f78c139 Remove unuseful file anymore (due too reintroduced packages) 2017-11-18 16:20:21 +01:00
Hugo Posnic
352ba03d02 Revert to initial gitignore 2017-11-18 16:19:21 +01:00
Hugo Posnic
278ef269cf Reintroduce threadpool and filesize packages 2017-11-18 16:16:59 +01:00
Hugo Posnic
25836634af setup.py: change requires from pyqt4 to pyqt5 2017-11-18 16:12:44 +01:00
Hugo Posnic
a24ef15ff5 Fix bug introduced by the first commit with list of images 2017-11-18 15:50:51 +01:00
Hugo Posnic
063d2b8adb Replace some old signals 2017-11-18 15:45:04 +01:00
Hugo Posnic
420c945f94 Just add a return line after the shebang 2017-11-18 15:34:22 +01:00
Hugo Posnic
bc8c665d40 Remove unuseful unicode call 2017-11-18 15:32:09 +01:00
Hugo Posnic
e71c22b519 Improve the .gitignore 2017-11-18 15:27:02 +01:00
Hugo Posnic
69fb5c9c88 Move todo in root for more visibility and convert it to markdown 2017-11-18 15:25:11 +01:00
Hugo Posnic
623922d12d Port quit signal to new system 2017-11-18 15:16:57 +01:00
Hugo Posnic
a20f7a5beb Fix version in setup.py 2017-11-18 15:09:25 +01:00
Hugo Posnic
a3d9735ef8 Fix canceling open image 2017-11-18 15:06:47 +01:00
Hugo Posnic
cd80b8c386 Replace setMargin with setContentsMargins 2017-11-18 14:57:02 +01:00
Hugo Posnic
8eca530275 First try to adopt Python3 and PyQt5 2017-11-18 14:44:11 +01:00
37 changed files with 572 additions and 760 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 bin/trimage
recursive-include desktop *.svg *.desktop
recursive-include src/ *.py *.png
recursive-include trimage/ *.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

44
README.md Normal file
View file

@ -0,0 +1,44 @@
### Made by [@kilianvalkhof](https://twitter.com/kilianvalkhof)
#### Other projects:
- 💻 [Polypane](https://polypane.app) - Develop responsive websites and apps twice as fast on multiple screens at once
- 🖌️ [Superposition](https://superposition.design) - Kickstart your design system by extracting design tokens from your website
- 🗒️ [FromScratch](https://fromscratch.rocks) - A smart but simple autosaving scratchpad
---
# 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.
## Installation instructions
Visit [Trimage.org](http://trimage.org) to install Trimage as a package.
## Building instructions
### Prerequisites
- PyQt5
- advpng
- jpegoptim
- optipng
- pngcrush
### Build from source
Build and install by running:
python setup.py build
sudo python setup.py install

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

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
#

9
debian/changelog vendored
View file

@ -1,3 +1,11 @@
trimage (1.0.6-0ubuntu1) bionic; urgency=low
* Migrate to python 3 and python-qt 5
* fix bug with hanging thread
* remove hurry.filesize package
-- Kilian Valkhof <kilian@kilianvalkhof.com> Tue, 12 Mar 2019 11:54:00 +0200
trimage (1.0.5-0ubuntu1) jaunty; urgency=low
* prevent images from becoming larger after recompression
@ -70,4 +78,3 @@ trimage (1.0.0b-0ubuntu1) jaunty; urgency=low
* Trimage image compressor
-- Kilian Valkhof <help@trimage.org> Tue, 23 Mar 2010 20:18:17 +0100

2
debian/compat vendored
View file

@ -1 +1 @@
7
11

9
debian/control vendored
View file

@ -2,15 +2,13 @@ Source: trimage
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
Standards-Version: 3.9.1
Build-Depends: debhelper (>=7), python3
Standards-Version: 4.3.0
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)
XB-Python-Version: ${python:Versions}
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)
Description: GUI and command-line interface to optimize image files
Trimage is a cross-platform GUI and command-line interface to optimize image
files via optipng, advpng, pngcrush and jpegoptim, depending on the filetype
@ -18,4 +16,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.

44
debian/copyright vendored
View file

@ -39,49 +39,6 @@ The Debian packaging is:
and is licensed under the MIT license, see above.
hurry.filesize is:
Copyright (C) Martijn Faassen, Startifact
License:
Zope Public License (ZPL) Version 2.1
A copyright notice accompanies this license document that identifies the
copyright holders. This license has been certified as open source. It has
also been designated as GPL compatible by the Free Software Foundation (FSF).
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions in source code must retain the accompanying copyright
notice, this list of conditions, and the following disclaimer.
2. Redistributions in binary form must reproduce the accompanying
copyright notice, this list of conditions, and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
3. Names of the copyright holders must not be used to endorse or promote
products derived from this software without prior written permission from
the copyright holders.
4. The right to distribute this software or to use it for any purpose does
not give you the right to use Servicemarks (sm) or Trademarks (tm) of the
copyright holders. Use of them is covered by separate agreement with the
copyright holders.
5. If any files are modified, you must cause the modified files to carry
prominent notices stating that you changed the files and the date of any
change.
Disclaimer
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
ThreadPool is:
Copyright (c) Morten Holdflod Moeller
@ -253,4 +210,3 @@ License:
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.

1
debian/pycompat vendored
View file

@ -1 +0,0 @@
2

1
debian/rules vendored Normal file → Executable file
View file

@ -1,4 +1,3 @@
#!/usr/bin/make -f
%:
dh $@

View file

@ -7,4 +7,4 @@ Type=Application
Exec=trimage
Categories=Application;Qt;Graphics;
StartupNotify=true
Keywords=compression;compressor;images;jpg;jpeg;png;web;

View file

@ -3,7 +3,7 @@
.\" This manual page is distributed under the terms
.\" of the GNU Free Documentation License version 1.3.
.\"
.TH TRIMAGE "1" "2011-07-11" "trimage 1.0.5" "User Commands"
.TH TRIMAGE "1" "2019-03-12" "trimage 1.0.6" "User Commands"
.SH NAME
trimage \- losslessly optimizing png and jpeg liles

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,41 +1,22 @@
#!/usr/bin/env python
import sys
win=(sys.platform == "win32")
if win:
import py2exe
sys.path.append("src/trimage")
#!/usr/bin/env python3
from distutils.core import setup
setup(name = "trimage",
version = "1.0.2",
version = "1.0.6",
description = "Trimage image compressor - A cross-platform tool for optimizing PNG and JPG files",
author = "Kilian Valkhof, Paul Chaplin",
author_email = "help@trimage.org",
url = "http://trimage.org",
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)"],
#for py2exe
windows=[r'src\trimage\trimage.py'],
zipfile=None,
options={"py2exe":{
"optimize":2,
"compressed":1,
"bundle_files":1,
"includes":["sip",],
"excludes":['email'],
},
},
scripts = ["bin/trimage"],
long_description = """Trimage is a cross-platform GUI and command-line interface to optimize image files via advpng, jpegoptim, optipng and pngcrush, 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 = ["PyQt5"]
)

View file

@ -1 +0,0 @@
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

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
@ -28,9 +30,6 @@ class ThreadPoolMixIn:
def __init__(self, threadpool=None):
if (threadpool == None):
threadpool = ThreadPool()
self.__private_threadpool = True
else:
self.__private_threadpool = False
self.__threadpool = threadpool
@ -50,10 +49,6 @@ class ThreadPoolMixIn:
def process_request(self, request, client_address):
self.__threadpool.add_job(self.process_request_thread, [request, client_address])
def shutdown(self):
if (self.__private_threadpool): self.__threadpool.shutdown()
class AddJobException(Exception):
'''
Exceptoion raised when a Job could not be added
@ -86,16 +81,16 @@ 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)
logger.warning("A job in the ThreadPool raised an exception: ", excep)
#else do nothing cause we don't know what to do...
return
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

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

View file

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 676 B

After

Width:  |  Height:  |  Size: 676 B

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 4.4 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 2 KiB

After

Width:  |  Height:  |  Size: 2 KiB

Before After
Before After

45
trimage/tools.py Normal file
View file

@ -0,0 +1,45 @@
#!/usr/bin/env python3
import sys
import errno
from subprocess import call, PIPE
def check_dependencies():
"""Check if the required command line apps exist."""
status = True
dependencies = {
"jpegoptim": "--version",
"optipng": "-v",
"advpng": "--version",
"pngcrush": "-version"
}
for elt in dependencies:
retcode = safe_call(elt + " " + dependencies[elt])
if retcode != 0:
status = False
print("[error] please install {}".format(elt), file=sys.stderr)
return status
def safe_call(command):
"""Cross-platform command-line check."""
while True:
try:
return call(command, shell=True, stdout=PIPE)
except OSError as e:
if e.errno == errno.EINTR:
continue
else:
raise
def human_readable_size(num, suffix="B"):
"""Bytes to a readable size format"""
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,32 +1,27 @@
#!/usr/bin/python
#!/usr/bin/env python3
import time
import sys
import errno
from os import listdir
from os import path
from os import remove
from os import access
from os import W_OK as WRITEABLE
from os import listdir, path, remove, access, W_OK
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 Queue import Queue
from ThreadPool import ThreadPool
from multiprocessing import cpu_count
from queue import Queue
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from ThreadPool import ThreadPool
from ui import Ui_trimage
VERSION = "1.0.5"
from tools import *
class StartQT4(QMainWindow):
VERSION = "1.0.6"
class StartQt(QMainWindow):
def __init__(self, parent=None):
QWidget.__init__(self, parent)
self.ui = Ui_trimage()
@ -40,10 +35,11 @@ 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():
# check if dependencies are installed
if not check_dependencies():
quit()
# add quit shortcut
@ -55,23 +51,17 @@ class StartQT4(QMainWindow):
# disable recompress
self.ui.recompress.setEnabled(False)
#self.ui.recompress.hide()
# make a worker thread
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")))
@ -82,11 +72,11 @@ class StartQT4(QMainWindow):
self.systemtray = Systray(self)
def commandline_options(self):
self.cli = False
"""Set up the command line options."""
self.cli = False
parser = OptionParser(version="%prog " + VERSION,
description="GUI front-end to compress png and jpg images via "
"optipng, advpng and jpegoptim")
"advpng, jpegoptim, optipng and pngcrush")
parser.set_defaults(verbose=True)
parser.add_option("-v", "--verbose", action="store_true",
@ -103,14 +93,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,11 +133,12 @@ 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,
images, _ = fd.getOpenFileNames(self,
"Select one or more image files to compress",
directory,
# this is a fix for file dialog differentiating between cases
@ -155,8 +146,8 @@ class StartQT4(QMainWindow):
self.settings.setValue("fdstate", QVariant(fd.saveState()))
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,8 +164,8 @@ 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
@ -191,7 +182,7 @@ class StartQT4(QMainWindow):
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)
for file in [file for file in listdir(dir) if not file in [".","..",".svn",".git",".hg",".bzr",".cvs"]]:
@ -204,7 +195,7 @@ class StartQT4(QMainWindow):
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)
if image.valid:
@ -214,7 +205,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
@ -247,52 +238,12 @@ class StartQT4(QMainWindow):
# enable recompress button
self.enable_recompress()
"""
Helper functions
"""
def enable_recompress(self):
"""Enable the recompress button."""
self.ui.recompress.setEnabled(True)
if QSystemTrayIcon.isSystemTrayAvailable() and not self.cli:
self.systemtray.recompress.setEnabled(True)
def checkapps(self):
"""Check if the required command line apps exist."""
exe = ".exe" if (sys.platform == "win32") else ""
status = False
retcode = self.safe_call("jpegoptim" + exe + " --version")
if retcode != 0:
status = True
sys.stderr.write("[error] please install jpegoptim")
retcode = self.safe_call("optipng" + exe + " -v")
if retcode != 0:
status = True
sys.stderr.write("[error] please install optipng")
retcode = self.safe_call("advpng" + exe + " --version")
if retcode != 0:
status = True
sys.stderr.write("[error] please install advancecomp")
retcode = self.safe_call("pngcrush" + exe + " -version")
if retcode != 0:
status = True
sys.stderr.write("[error] please install pngcrush")
return status
def safe_call(self, command):
""" cross-platform command-line check """
while True:
try:
return call(command, shell=True, stdout=PIPE)
except OSError, e:
if e.errno == errno.EINTR:
continue
else:
raise
def hide_main_window(self):
if self.isVisible():
self.hide()
@ -309,7 +260,6 @@ class StartQT4(QMainWindow):
class TriTableModel(QAbstractTableModel):
def __init__(self, parent, imagelist, header, *args):
"""
@param parent Qt parent object.
@ -351,15 +301,15 @@ class TriTableModel(QAbstractTableModel):
class ImageRow:
def __init__(self, image, waitingIcon=None):
"""Build the information visible in the table image row."""
self.image = image
d = {
'shortname': lambda i: self.statusStr() % i.shortname,
'oldfilesizestr': lambda i: size(i.oldfilesize, system=alternative)
'filename_w_ext': lambda i: self.statusStr().format(i.filename_w_ext),
'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))
@ -367,7 +317,7 @@ class ImageRow:
'icon': lambda i: i.icon if i.compressed else waitingIcon,
'fullpath': lambda i: i.fullpath, #only used by cli
}
names = ['shortname', 'oldfilesizestr', 'newfilesizestr',
names = ['filename_w_ext', 'oldfilesizestr', 'newfilesizestr',
'ratiostr', 'icon']
for i, n in enumerate(names):
d[i] = d[n]
@ -377,45 +327,38 @@ class ImageRow:
def statusStr(self):
"""Set the status message."""
if self.image.failed:
return "ERROR: %s"
return "ERROR: {0}"
if self.image.compressing:
message = "Compressing %s..."
message = "Compressing {0}..."
return message
if not self.image.compressed and self.image.recompression:
return "Queued for recompression..."
return "Queued for recompression {0}..."
if not self.image.compressed:
return "Queued..."
return "%s"
return "Queued {0}..."
return "{0}"
def __getitem__(self, key):
return self.d[key](self.image)
class Image:
def __init__(self, fullpath):
""" gather image information. """
"""Gather image information."""
self.valid = False
self.reset()
self.fullpath = fullpath
if path.isfile(self.fullpath) and access(self.fullpath, WRITEABLE):
self.filetype = determinetype(self.fullpath)
self.filename_w_ext = path.basename(self.fullpath)
self.filename, self.filetype = path.splitext(self.filename_w_ext)
if path.isfile(self.fullpath) and access(self.fullpath, W_OK):
self.filetype = self.filetype[1:].lower()
if self.filetype == "jpg":
self.filetype = "jpeg"
if self.filetype in ["jpeg", "png"]:
oldfile = QFileInfo(self.fullpath)
self.shortname = oldfile.fileName()
self.oldfilesize = oldfile.size()
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
@ -429,13 +372,13 @@ class Image:
file)"
self.reset()
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 -f --strip-all '%(file)s'",
"png": "optipng -force -o7 '%(file)s'&&advpng -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 + '~')
# create a backup file
backupfullpath = '/tmp/' + self.filename_w_ext
copy(self.fullpath, backupfullpath)
try:
retcode = call(runString[self.filetype] % {"file": self.fullpath},
shell=True, stdout=PIPE)
@ -445,13 +388,13 @@ class Image:
self.newfilesize = QFile(self.fullpath).size()
self.compressed = True
# Checks the new file and copy the backup
# checks the new file and copy the backup
if self.newfilesize >= self.oldfilesize:
copy(self.fullpath + '~', self.fullpath)
copy(backupfullpath, self.fullpath)
self.newfilesize = self.oldfilesize
# Removes the backup file
remove(self.fullpath + '~')
# removes the backup file
remove(backupfullpath)
else:
self.failed = True
self.compressing = False
@ -460,15 +403,13 @@ class Image:
class Worker(QThread):
update_ui_signal = pyqtSignal()
def __init__(self, parent=None):
QThread.__init__(self, parent)
self.toDisplay = Queue()
self.threadpool = ThreadPool(max_workers=cpu_count())
def __del__(self):
self.threadpool.shutdown()
def compress_file(self, images, showapp, verbose, imagelist):
"""Start the worker thread."""
for image in images:
@ -488,7 +429,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,11 +438,10 @@ 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):
def __init__(self, parent):
QWidget.__init__(self)
self.parent = parent
@ -511,15 +451,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 +466,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 +490,7 @@ class Systray(QWidget):
if __name__ == "__main__":
app = QApplication(sys.argv)
myapp = StartQT4()
myapp = StartQt()
if myapp.showapp:
myapp.show()

View file

@ -1,8 +1,16 @@
from PyQt4.QtCore import *
from PyQt4.QtGui import *
#!/usr/bin/env python3
from os import path
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
class TrimageTableView(QTableView):
drop_event_signal = pyqtSignal(list)
"""Init the table drop event."""
def __init__(self, parent=None):
super(TrimageTableView, self).__init__(parent)
@ -21,19 +29,19 @@ 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 """
"""Get the correct link to the images used in the UI."""
imagelink = path.join(path.dirname(path.dirname(path.realpath(__file__))), "trimage/" + image)
return imagelink
def setupUi(self, trimage):
""" Setup the entire UI """
"""Setup the entire UI."""
trimage.setObjectName("trimage")
trimage.resize(600, 170)
@ -44,7 +52,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 +68,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 +76,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 +101,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)
@ -141,26 +149,24 @@ class Ui_trimage(object):
QMetaObject.connectSlotsByName(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 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,13 +1,18 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf8">
<meta charset="utf8" />
<title>Trimage (lossless) image compressor</title>
<link href="https://raw.github.com/Kilian/sencss/master/source/sen.css" rel="stylesheet" type="text/css">
<link
href="https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.1/normalize.min.css"
rel="stylesheet"
type="text/css"
/>
<style>
body {
background:#fff
font-size:13px;
font-family:sans-serif;
}
#wrap {
position:relative;
@ -69,81 +74,103 @@
<body>
<div id="wrap">
<h1><img src="trimage-icon.png" alt=""> Trimage image compressor &ndash; 1.0.5</h1>
<span class="subtitle">A cross-platform tool for losslessly optimizing PNG and JPG files.</span>
<p class="tri">Trimage is a cross-platform GUI and command-line interface to optimize image
files for websites, using <a href="http://optipng.sourceforge.net/">optipng</a>, <a href="http://pmt.sourceforge.net/pngcrush/">pngcrush</a>,
<a href="http://advancemame.sourceforge.net/comp-readme.html">advpng</a> and
<a href="http://www.kokkonen.net/tjko/projects.html">jpegoptim</a>, depending on the filetype
(currently, PNG and JPG files are supported). It was inspired by
<a href="http://imageoptim.pornel.net/">imageoptim</a>. All image files are losslessy compressed
on the highest available compression levels, and EXIF and other metadata is removed. Trimage gives you various input functions to fit your
own workflow: A regular file dialog, dragging and dropping and various command line options.</p>
<h1>
<img src="trimage-icon.png" alt="" /> Trimage image compressor &ndash;
1.0.6
</h1>
<span class="subtitle"
>A cross-platform tool for losslessly optimizing PNG and JPG files for
web.</span
>
<p class="tri">
Trimage is a cross-platform GUI and command-line interface to optimize
image files for websites, using
<a href="http://optipng.sourceforge.net/">optipng</a>,
<a href="http://pmt.sourceforge.net/pngcrush/">pngcrush</a>,
<a href="http://advancemame.sourceforge.net/comp-readme.html">advpng</a>
and <a href="http://www.kokkonen.net/tjko/projects.html">jpegoptim</a>,
depending on the filetype (currently, PNG and JPG files are supported).
It was inspired by
<a href="http://imageoptim.pornel.net/">imageoptim</a>. All image files
are losslessy compressed on the highest available compression levels,
and EXIF and other metadata is removed. Trimage gives you various input
functions to fit your own workflow: A regular file dialog, dragging and
dropping and various command line options.
</p>
<h2>Trimage in action</h2>
<img src="image.png" alt="a screenshot of Trimage">
<img src="image.png" alt="a screenshot of Trimage" />
<div class="block2">
<h2>Download</h2>
<h3><img src="debian.png" alt=""> Debian (sid)</h3>
<h3><img src="debian.png" alt="" /> Debian (sid)</h3>
<p>Trimage is available in the official Debian Sid repositories:</p>
<ol>
<li><code>sudo apt-get install trimage</code></li>
</ol>
<h3><img src="ubuntu.png" alt=""> Ubuntu</h3>
<p>If you're on Natty (11.04), Trimage is available in the official repositories:</p>
<a href="https://apps.ubuntu.com/cat/applications/trimage/"><img src="http://developer.ubuntu.com/wp-content/uploads/2012/06/downloadonubuntubutton.png" title="Download for Ubuntu" alt="Download for Ubuntu button" width="122" height="49" /></a>
<h3><img src="ubuntu.png" alt="" /> Ubuntu</h3>
<p>Trimage is available in the official repositories:</p>
<a href="https://apps.ubuntu.com/cat/applications/trimage/"
>Download for Ubuntu</a
>
<p>Alternatively:</p>
<ol>
<li><code>sudo apt-get install trimage</code></li>
</ol>
<p>If you're on Maveric (10.10), Karmic (9.10) or Lucid (10.04), type the following commands into your console:</p>
<ol>
<li><code>sudo add-apt-repository ppa:kilian/trimage</code></li>
<li><code>sudo apt-get update</code></li>
<li><code>sudo apt-get install trimage</code></li>
</ol>
<p>If you are still on Jaunty, read <a href="https://launchpad.net/+help/soyuz/ppa-sources-list.html">this guide</a> on installing PPA's.</p>
<h3><img src="arch.png" alt=""> Arch Linux</h3>
<h3><img src="arch.png" alt="" /> Arch Linux</h3>
Trimage is available from AUR, to install, type:
<ol>
<li><code>yaourt -S trimage-git</code> </li>
<li><code>yaourt -S trimage</code></li>
</ol>
<h3><img src="mandriva.png" alt=""> Mandriva Linux 2010.1</h3>
Trimage is available Via two RPMs provided by <a href="http://mib.pianetalinux.org/mib/quick/basic-rpms/mib-rpms/918-trimage-105">Mandriva international backports</a>
<ol>
<li><a href="http://mib.pianetalinux.org/2010.1/32/basic/trimage-1.0.5-69mib2010.1.noarch.rpm">Trimage 1.0.5 32bit</a></li>
<li><a href="http://mib.pianetalinux.org/2010.1/64/basic/trimage-1.0.5-69mib2010.1.noarch.rpm">Trimage 1.0.5 63bit</a></li>
</ol>
<h3><img src="opensuse.png" alt=""> OpenSuse</h3>
<p>Trimage is available for a variety of versions: 11.3, 11.4 and Factory and SLE. You can find them on <a href="http://software.opensuse.org/search?q=Trimage&include_home=true">software.opensuse.org</a>.</p>
<h3><img src="linux.png" alt=""> Other *nix</h3>
<h3><img src="macos.png" alt="" /> macOS</h3><!-- Attribution for the image: VICDJES21 / CC BY-SA (https://creativecommons.org/licenses/by-sa/4.0) -->
Trimage is available from Homebrew, to install, type:
<ol>
<li><code>brew install trimage</code></li>
</ol>
<p>Launch by executing <code>trimage</code> in Terminal.app</p>
<h3><img src="linux.png" alt="" /> Other *nix</h3>
<ol>
<li>Download the source via git or bzr (see repositories)</li>
<li>Make sure you have all the requirements installed (see requirements)</li>
<li>
Make sure you have all the requirements installed (see requirements)
</li>
<li>Enter <code>python setup.py install</code> into your console</li>
<li>Launch by executing <code>trimage</code></li>
</ol>
<p>Help us make .deb's, rpms's etc: <a href="mailto:help@trimage.org">contact us</a></p>
<h3><img src="mac.png" alt=""> Mac</h3>
<p>Trimage should be able to run on Mac. <a href="mailto:help@trimage.org">Help us with this</a></p>
<p>
Help us make .snaps, .appimages etc:
<a href="mailto:help@trimage.org">contact us</a> or
<a href="https://github.com/kilian/trimage/pulls"
>open a pull request</a
>
</p>
<!--
<h3><img src="windows.png" alt=""> Windows</h3>
<p>Trimage should be able to run on Windows. <a href="mailto:help@trimage.org">Help us with this</a></p>
-->
</div>
<div class="block">
<h2>Repositories</h2>
<p><strong>Git:</strong> Trimage is primarily developed on <a href="http://github.com/Kilian/Trimage">GitHub</a>.</p>
<p><strong>Bzr:</strong> Trimage is also available on <a href="https://launchpad.net/trimage">Launchpad</a>.</p>
<p>
<strong>Git:</strong> Trimage is primarily developed on
<a href="http://github.com/Kilian/Trimage">GitHub</a>.
</p>
<p>
<strong>Bzr:</strong> Trimage is also available on
<a href="https://launchpad.net/trimage">Launchpad</a>.
</p>
<p>Trimage is MIT licenced. We encourage contributions via GitHub.</p>
</div>
<div class="block">
<h2>Thanks</h2>
<p>The following people helped develop Trimage:</p>
<ul>
<li><a href="https://hugo-posnic.fr/">Hugo Posnic</a></li>
<li>Neil Wallace</li>
<li>Jeroen Goudsmit</li>
<li>Tarnay Kálmán</li>
@ -151,21 +178,11 @@
<li>Kyrill Detinov</li>
</ul>
</div>
<div class="block">
<h2>Donate</h2>
<p>If you enjoy using Trimage, please buy us a coffee or a beer :)</p>
<a href='http://www.pledgie.com/campaigns/9607'><img alt='Click here to lend your support to: Trimage and make a donation at www.pledgie.com !' src='http://www.pledgie.com/campaigns/9607.png?skin_name=chrome' border='0' /></a>
<script type="text/javascript">
var flattr_url = 'http://trimage.org';
var flattr_btn='compact';
</script>
<script src="http://api.flattr.com/button/load.js" type="text/javascript"></script>
</div>
<div class="block">
<h2>Requirements</h2>
<ul>
<li>python <em>2.6</em></li>
<li>python-qt4 <em>4.4</em></li>
<li>python <em>3</em></li>
<li>python-qt5 <em>5</em></li>
<li>optipng <em>0.6.2.1</em></li>
<li>pngcrush <em>1.6.7</em></li>
<li>advancecomp <em>1.15</em></li>
@ -192,28 +209,18 @@
</div>
<div class="block">
<h2>Help</h2>
<p>Please use <a href="http://github.com/Kilian/Trimage">GitHub</a> for reporting bugs and email <a href="mailto:help@trimage.org">help@trimage.org</a> for general questions (though we are not a helpdesk!)</p>
<p>
Please use <a href="https://github.com/Kilian/Trimage">GitHub</a> for
reporting bugs and email
<a href="mailto:help@trimage.org">help@trimage.org</a> for general
questions (though we are not a helpdesk!)
</p>
</div>
<h2>Planned features</h2>
<p>Version 1.1.0 final:</p>
<ul>
<li>Expand command line options</li>
<li>General refactoring</li>
</ul>
<p>Version 1.1.1 final:</p>
<ul>
<li>Use multiprocessing instead of threads</li>
</ul>
<p>Beyond that</p>
<ul>
<li>Deletion of rows in the table view</li>
<li>Integration with online services such as punypng</li>
<li><a href="mailto:help@trimage.org">Suggest something</a></li>
</ul>
<p class="footer">Trimage is &copy; 2010 <a href="http://kilianvalkhof.com">Kilian Valkhof</a>, <a href="http://paulchaplin.com">Paul Chaplin</a>
<p class="footer">
Trimage is &copy; 2010&ndash;2019
<a href="http://kilianvalkhof.com">Kilian Valkhof</a>,
<a href="http://paulchaplin.com">Paul Chaplin</a>
</p>
</div>
</body>
</html>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 891 B

BIN
website/macos.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 835 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB