Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 35 additions & 1 deletion photocollage/gtkgui.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@

from photocollage import APP_NAME, artwork, collage, render
from photocollage.render import PIL_SUPPORTED_EXTS as EXTS
from photocollage.render import QUALITIES, QUALITY_FAST, QUALITY_BEST,\
QUALITY_SKEL


gettext.textdomain(APP_NAME)
Expand Down Expand Up @@ -168,6 +170,7 @@ def __init__(self):
self.border_c = "black"
self.out_w = 800
self.out_h = 600
self.quality = QUALITY_FAST

self.opts = Options()

Expand Down Expand Up @@ -344,6 +347,7 @@ def on_fail(exception):
border_width=self.opts.border_w * max(collage.page.w,
collage.page.h),
border_color=self.opts.border_c,
quality=QUALITY_FAST, # for preview, use NEAREST
on_update=gtk_run_in_main_thread(on_update),
on_complete=gtk_run_in_main_thread(on_complete),
on_fail=gtk_run_in_main_thread(on_fail))
Expand Down Expand Up @@ -392,7 +396,8 @@ def save_poster(self, button):
enlargement = float(self.opts.out_w) / collage.page.w
collage.page.scale(enlargement)

dialog = Gtk.FileChooserDialog(_("Save image"), button.get_toplevel(),
dialog = Gtk.FileChooserDialog(_("Save image"),
button.get_toplevel(),
Gtk.FileChooserAction.SAVE)
dialog.add_button(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL)
dialog.add_button(Gtk.STOCK_OK, Gtk.ResponseType.OK)
Expand Down Expand Up @@ -427,6 +432,7 @@ def on_fail(exception):
collage.page, output_file=savefile,
border_width=self.opts.border_w * max(collage.page.w,
collage.page.h),
quality=self.opts.quality, # for saving, use user setting
border_color=self.opts.border_c,
on_update=gtk_run_in_main_thread(on_update),
on_complete=gtk_run_in_main_thread(on_complete),
Expand Down Expand Up @@ -714,6 +720,29 @@ def apply_template(combo):

vbox.pack_start(Gtk.SeparatorToolItem(), True, True, 0)

label = Gtk.Label(xalign=0)
label.set_markup("<big><b>%s</b></big>" % _("Image quality"))
vbox.pack_start(label, False, False, 0)

box = Gtk.Box(spacing=6)
vbox.pack_start(box, False, False, 0)
label = Gtk.Label(_("Resizing method:"), xalign=1)
box.pack_start(label, False, False, 0)

self.qualities = (
(QUALITIES[QUALITY_SKEL]['str'], QUALITY_SKEL),
(QUALITIES[QUALITY_FAST]['str'], QUALITY_FAST),
(QUALITIES[QUALITY_BEST]['str'], QUALITY_BEST),
)

self.cmb_quality = Gtk.ComboBoxText()
for q, r in self.qualities:
self.cmb_quality.append(q, q)
self.cmb_quality.set_active(parent.opts.quality - 1)
box.pack_end(self.cmb_quality, False, False, 0)

vbox.pack_start(Gtk.SeparatorToolItem(), True, True, 0)

self.show_all()

def validate_int(self, entry):
Expand All @@ -737,6 +766,11 @@ def apply_opts(self, opts):
opts.out_h = int(self.etr_outh.get_text() or '1')
opts.border_w = float(self.etr_border.get_text() or '0') / 100.0
opts.border_c = self.colorbutton.get_rgba().to_string()
# TODO: test following line; not sure it works that easily.
q = self.cmb_quality.get_model()[
self.cmb_quality.get_active_iter()][1]
if q:
opts.quality = dict(self.qualities)[q]


class ComputingDialog(Gtk.Dialog):
Expand Down
45 changes: 31 additions & 14 deletions photocollage/render.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,32 @@
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

import gettext
import random
from threading import Thread
import time

import PIL.Image
import PIL.ImageDraw

from photocollage import APP_NAME
from photocollage.collage import Photo

gettext.textdomain(APP_NAME)
_ = gettext.gettext
_n = gettext.ngettext

QUALITY_SKEL = 0
QUALITY_FAST = 1
QUALITY_BEST = 2
QUALITY_SKEL = 1
QUALITY_FAST = 2
QUALITY_BEST = 3
QUALITIES = {
QUALITY_SKEL: {'str': _("Skeleton (no rendering)"),
'filter': None},
QUALITY_FAST: {'str': _("Standard (nearest neighbor; quicker)"),
'filter': PIL.Image.NEAREST},
QUALITY_BEST: {'str': _("Best (antialiasing; slower)"),
'filter': PIL.Image.ANTIALIAS},
}


class PIL_SUPPORTED_EXTS(object):
Expand Down Expand Up @@ -213,21 +226,24 @@ def resize_photo(self, cell, use_cache=False):
elif cell.photo.orientation == 8:
img = img.rotate(90, expand=True)

if self.quality == QUALITY_FAST:
method = PIL.Image.NEAREST
else:
method = PIL.Image.ANTIALIAS
method = QUALITIES[self.quality]['filter']

shape = img.size[0] * cell.h - img.size[1] * cell.w
if shape > 0: # image is too thick
img = img.resize((int(round(cell.h * img.size[0] / img.size[1])),
int(round(cell.h))), method)
img = img.resize(
(int(round(cell.h * img.size[0] / img.size[1])),
int(round(cell.h))),
method)
elif shape < 0: # image is too tall
img = img.resize((int(round(cell.w)),
int(round(cell.w * img.size[1] / img.size[0]))),
method)
img = img.resize(
(int(round(cell.w)),
int(round(cell.w * img.size[1] / img.size[0]))),
method)
else:
img = img.resize((int(round(cell.w)), int(round(cell.h))), method)
img = img.resize(
(int(round(cell.w)),
int(round(cell.h))),
method)

# Save this new image to cache (if it is larger than the previous one)
if (use_cache and (cell.photo.filename not in cache or
Expand Down Expand Up @@ -269,7 +285,8 @@ def run(self):

if self.quality != QUALITY_SKEL:
n = sum([len([cell for cell in col.cells if not
cell.is_extension()]) for col in self.page.cols])
cell.is_extension()])
for col in self.page.cols])
i = 0.0
if self.on_update:
self.on_update(canvas, 0.0)
Expand Down