Mercurial > hg > pub > prymula > scripts
diff photocrop/src/photocrop.py @ 0:dcd610585610
INIT
author | prymula <prymula76@outlook.com> |
---|---|
date | Thu, 21 Sep 2023 22:32:14 +0200 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/photocrop/src/photocrop.py Thu Sep 21 22:32:14 2023 +0200 @@ -0,0 +1,1164 @@ +#!/usr/bin/env python3 +# Photo Crop - photo crop to size app to print in the most popular photo paper sizes +# author: Przemysław R. Pietraszczyk +# license: GPL v.2 +# date 21-01-2022 +# editor: Geany + +import sys +import cairo +import gi, os +import time +gi.require_version("Gtk", "3.0") +from gi.repository import Gtk, GdkPixbuf, Gdk +from gi.repository.GdkPixbuf import Pixbuf + +UI_INFO = """ +<ui> + <menubar name='MenuBar'> + <menu action='FileMenu'> + <menuitem action='FileLoad' /> + <menuitem action='FileSave' /> + <menuitem action='FilePrint' /> + <separator /> + <menuitem action='FileQuit' /> + </menu> + <menu action='EditMenu'> + <menuitem action='Rotate'/> + </menu> + <menu action='InfoMenu'> + <menuitem action='Help'/> + <menuitem action='About'/> + <separator /> + <menuitem action='License'/> + </menu> + </menubar> + +</ui> +""" + +""" +# szkielet z podmenu +<ui> + <menubar name='MenuBar'> + <menu action='FileMenu'> + <menu action='FileLoad'> + <menuitem action='LoadImg' /> + </menu> + <menuitem action='FilePrint' /> + <separator /> + <menuitem action='FileQuit' /> + </menu> + <menu action='InfoMenu'> + <menuitem action='Help'/> + <menuitem action='About'/> + </menu> + </menubar> +</ui> +""" + +grid = Gtk.Grid() +rotate = False +file_img_selected = "" + +def get_resource_path(rel_path): + dir_of_py_file = os.path.dirname(__file__) + rel_path_to_resource = os.path.join(dir_of_py_file, rel_path) + abs_path_to_resource = os.path.abspath(rel_path_to_resource) + return abs_path_to_resource + +class FileChooserIMGLoad(Gtk.Window): + def __init__(self): + Gtk.Window.__init__(self, title="Selection of graphic files") + global file_img_selected + + dialog = Gtk.FileChooserDialog(title="Selection of graphic files", parent=self, action=Gtk.FileChooserAction.OPEN) + dialog.add_buttons( + Gtk.STOCK_CANCEL, + Gtk.ResponseType.CANCEL, + Gtk.STOCK_OPEN, + Gtk.ResponseType.OK, + ) + + self.add_filters(dialog) + + response = dialog.run() + if response == Gtk.ResponseType.OK: + print("Open clicked") + print("File selected: " + dialog.get_filename()) + file_img_selected=dialog.get_filename() + elif response == Gtk.ResponseType.CANCEL: + print("Cancel clicked") + + dialog.destroy() + + def add_filters(self, dialog): + + filter_jpeg = Gtk.FileFilter() + filter_jpeg.set_name("Files JPEG") + filter_jpeg.add_mime_type("image/jpeg") + dialog.add_filter(filter_jpeg) + + filter_png = Gtk.FileFilter() + filter_png.set_name("Files PNG") + filter_png.add_mime_type("image/png") + dialog.add_filter(filter_png) + """ + filter_png = Gtk.FileFilter() + filter_png.set_name("Files TIFF") + filter_png.add_mime_type("image/tiff") + dialog.add_filter(filter_png) + """ + +class FileChooserIMGSave(Gtk.Window): + def __init__(self): + Gtk.Window.__init__(self, title="Save the cropped photo") + global file_img_selected + + dialog = Gtk.FileChooserDialog(title="Save the cropped photo", parent=self, action=Gtk.FileChooserAction.SAVE) + dialog.add_buttons( + Gtk.STOCK_CANCEL, + Gtk.ResponseType.CANCEL, + Gtk.STOCK_SAVE, + Gtk.ResponseType.OK, + ) + + self.add_filters(dialog) + + response = dialog.run() + if response == Gtk.ResponseType.OK: + print("Open clicked") + print("File selected: " + dialog.get_filename()) + file_img_selected=dialog.get_filename() + elif response == Gtk.ResponseType.CANCEL: + print("Cancel clicked") + + dialog.destroy() + + def add_filters(self, dialog): + + filter_jpeg = Gtk.FileFilter() + filter_jpeg.set_name("Files JPEG") + filter_jpeg.add_mime_type("image/jpeg") + dialog.add_filter(filter_jpeg) + + filter_png = Gtk.FileFilter() + filter_png.set_name("Files PNG") + filter_png.add_mime_type("image/png") + dialog.add_filter(filter_png) + """ + filter_png = Gtk.FileFilter() + filter_png.set_name("Files TIFF") + filter_png.add_mime_type("image/tiff") + dialog.add_filter(filter_png) + """ + + +class DialogWarning(Gtk.Dialog): + def __init__(self, parent): + Gtk.Dialog.__init__(self, title="Attention!", transient_for=parent, flags=0) + self.props.border_width = 20 + self.add_buttons( + Gtk.STOCK_OK, Gtk.ResponseType.OK + ) + self.set_default_size(150, 100) + label1 = Gtk.Label(label="The frame is outside the canvas!\n") + box = self.get_content_area() + box.add(label1) + self.show_all() + +class DialogCropWarning(Gtk.Dialog): + def __init__(self, parent): + Gtk.Dialog.__init__(self, title="Attention!", transient_for=parent, flags=0) + self.props.border_width = 20 + self.add_buttons( + Gtk.STOCK_OK, Gtk.ResponseType.OK + ) + self.set_default_size(150, 100) + label1 = Gtk.Label(label="Crop the photo first!\n") + box = self.get_content_area() + box.add(label1) + self.show_all() + +class DialogHelp(Gtk.Dialog): + def __init__(self, parent): + Gtk.Dialog.__init__(self, title="Help", transient_for=parent, flags=0) + self.props.border_width = 20 + self.add_buttons( + Gtk.STOCK_OK, Gtk.ResponseType.OK + ) + + self.set_default_size(150, 100) + label1 = Gtk.Label(label="An application for cropping photos to the most popular\nformats [13x18, 10x15, A4]\n\nScaling the size of the frame - mouse wheel with the CTRL key pressed\nMoving the frame - pressed LMB and moving the mouse\nin the desired direction.") + #label2 = Gtk.Label(lanel="") + box = self.get_content_area() + box.add(label1) + #box.add(label2) + self.show_all() + +class DialogAbout(Gtk.Dialog): + def __init__(self, parent): + Gtk.Dialog.__init__(self, title="About", transient_for=parent, flags=0) + self.props.border_width = 20 + self.add_buttons( + Gtk.STOCK_OK, Gtk.ResponseType.OK + ) + + self.set_default_size(150, 100) + + label = Gtk.Label(label="\tThe application is based on:") + box = self.get_content_area() + box.add(label) + + button = Gtk.LinkButton("https://python-gtk-3-tutorial.readthedocs.io/", label="https://python-gtk-3-tutorial.readthedocs.io/") + box.add(button) + + label2 = Gtk.Label(label="\n\tVersion: 0.230112-1~alpha\n\n\tPrzemysław R. Pietraszczyk\n\n\t\t January 2022\n\n\n") + box.add(label2) + + + button = Gtk.LinkButton("https://prymula.ct8.pl", label="Site") + box.add(button) + + self.show_all() + +class DialogLicense(Gtk.Dialog): + def __init__(self, parent): + Gtk.Dialog.__init__(self, title="License", transient_for=parent, flags=0) + self.props.border_width = 20 + self.add_buttons( + Gtk.STOCK_OK, Gtk.ResponseType.OK + ) + + self.set_default_size(150, 100) + + label = Gtk.Label(label="This program is distributed without any warranty. More information:\n") + + box = self.get_content_area() + box.add(label) + + button = Gtk.LinkButton("https://www.gnu.org/licenses/old-licenses/gpl-2.0.html", label="GNU General License version => 2") + box.add(button) + + self.show_all() + +class Brush(object): + + default_rgba_color = (0, 0, 0, 1) + + def __init__(self, width=None, rgba_color=None): + + if rgba_color is None: + rgba_color = self.default_rgba_color + + if width is None: + width = 3 + + self.__width = width + self.__rgba_color = rgba_color + self.__stroke = [] + self.__current_line = [] + + def _line_ended(self): + self.__stroke.append(self.__current_line.copy()) + self.__current_line = [] + + def _add_point(self, point): + self.__current_line.append(point) + + def _draw(self, cairo_context): + + cairo_context.set_source_rgba(*self.__rgba_color) + cairo_context.set_line_width(self.__width) + cairo_context.set_line_cap(cairo.LINE_CAP_ROUND) + + cairo_context.new_path() + for line in self.__stroke: + for x, y in line: + cairo_context.line_to(x, y) + cairo_context.new_sub_path() + + for x, y in self.__current_line: + cairo_context.line_to(x, y) + + cairo_context.stroke() + + +# ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ # +# ~ Getters & Setters ~ # +# ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ # + + def _get_width(self): + return self.__width + + def _set_width(self, width): + self.__width = width + + def _get_rgba_color(self): + return self.__rgba_color + + def _set_rgba_color(self, rgba_color): + self.__rgba_color = rgba_color + + def _get_stroke(self): + return self.__stroke + + def _get_current_line(self): + return self.__current_line + +class MyWindow(Gtk.Window): + + def __init__(self): + super().__init__() + + self.init_ui() + + def on_drawing_area_draw(self, drawable, cairo_context): + global rotate + + start = time.time() + self.brush = Brush() + + # DrawingArea size depends on Pixbuf size + #self.drawing_area.get_window().resize(self.displayed_pixbuf.get_width(), + # self.displayed_pixbuf .get_height()) + #self.drawing_area.set_size_request(self.displayed_pixbuf.get_width(), + # self.displayed_pixbuf.get_height()) + + + # (x, y) offsets + pixbuf_x = 0 #int(self.viewport.get_hadjustment().get_value()) + pixbuf_y = 0 # int(self.viewport.get_vadjustment().get_value()) + + # Width and height of the image's clip + width = cairo_context.get_target().get_width() + height = cairo_context.get_target().get_height() + + if width > 0 and height > 0: + + # Draw created area of the Sample's Pixbuf + Gdk.cairo_set_source_pixbuf(cairo_context, self.pixbuf_view, pixbuf_x, pixbuf_y) + + cairo_context.paint() + + if self.border_visible == True: + # Draw brush strokes + self.brush._add_point((self.border_x, self.border_y)) + self.brush._add_point((self.border_width, self.border_y)) + self.brush._add_point((self.border_width, self.border_y+self.border_height)) + self.brush._add_point((self.border_x, self.border_y+self.border_height)) + self.brush._add_point((self.border_x, self.border_y)) # nie działa ? + + self.brush._draw(cairo_context) + + end = time.time() + #print(f"Runtime of the program is {end - start}") + + + def set_ratio_border_size(self): + + self.border_x = 0 + self.border_y = 0 + + if self.format_size == "10x15": + if self.horizontal == True and self.vertical == False: + single = self.picture_view_height*0.5 + self.border_height = single + self.border_width = single*1.4 + #self.look = "horizontal" + #self.border_type = "horizontal" + elif self.horizontal == False and self.vertical == True: + single = self.picture_view_width*0.5 + self.border_width = single + self.border_height = single*1.4 + #self.look = "vertical" + #self.border_type = "vertical" + elif self.horizontal == False and self.vertical == False: + self.border_height = self.picture_view_height + self.border_width = self.picture_view_width + + elif self.format_size == "13x18": + if self.horizontal == True and self.vertical == False: + single = self.picture_view_height*0.5 + self.border_height = single + self.border_width = single*1.42 + elif self.horizontal == False and self.vertical == True: + single = self.picture_view_width*0.5 + self.border_width = single + self.border_height = single*1.42 + elif self.horizontal == False and self.vertical == False: + self.border_height = self.picture_view_height + self.border_width = self.picture_view_width + + elif self.format_size == "A4": + if self.horizontal == True and self.vertical == False: + single = self.picture_view_height*0.5 + self.border_height = single + self.border_width = single*1.4 + elif self.horizontal == False and self.vertical == True: + single = self.picture_view_width*0.5 + self.border_width = single + self.border_height = single*1.4 + elif self.horizontal == False and self.vertical == False: + self.border_height = self.picture_view_height + self.border_width = self.picture_view_width + + + + # ustaw proporcje dla obrazu w kontrolce + def set_ratio_picture_view(self): + self.picture_orig_width = float(self.pixbuf_orig.get_width()) + self.picture_orig_height = float(self.pixbuf_orig.get_height()) + #if self.format_size == "10x15": + #self.picture_orig_x = 0 + #self.picture_orig_y = 0 + + if self.picture_orig_width > self.picture_orig_height: + self.picture_view_width = 586.66 #600 + m = self.picture_orig_width / 586.66 #600 + self.picture_view_height = self.picture_orig_height/m + if self.picture_orig_height > self.picture_orig_width: + self.picture_view_height = 586.66 #600 + m = self.picture_orig_height / 586.66 #600 + self.picture_view_width = self.picture_orig_width/m + + # Zapamiętanie rozmiaru obrazka dla kontrolki + self.orig_ratio_width = self.picture_view_width + self.orig_ratio_height = self.picture_view_height + + + + # ustaw proporcje dla obrazu w kontrolce ppo rotacji + def set_ratio_picture_view_after_rotation(self): + + self.picture_tmp_width = self.border_width - self.border_x + self.picture_tmp_height = self.border_height - self.border_y + + if self.border_x != 0 : + bx = self.picture_orig_width / self.border_x + crop_x = self.picture_tmp_width / bx + else: + crop_x = 0 + + if self.border_y != 0: + by = self.picture_orig_height / self.border_y + crop_y = self.picture_tmp_height / by + else: + crop_y = 0 + + + self.picture_orig_x = crop_x + self.picture_orig_y = crop_y + """ + W zależności jaka była pierwotnie orientacja zdjęcia, po obrocie + jest ono odpowiedio przycinane + """ + print ("ORIG: "+self.look) + if self.look == "vertical": + if self.border_type == "horizontal": + bw = self.picture_orig_width / (self.border_width - self.border_x) + self.picture_tmp_width = self.picture_orig_width / bw - crop_x + # w tym wypadku 'y' bez odejmowania gdyż skróciło by to fotografie w pione + bh = self.picture_orig_height / self.border_height + self.picture_tmp_height = self.picture_orig_height / bh + + elif self.border_type == "vertical": + bw = self.picture_orig_width / (self.border_width - self.border_x) + self.picture_tmp_width = self.picture_orig_width / bw - crop_x + + bh = self.picture_orig_height / (self.border_height - self.border_y) + self.picture_tmp_height = self.picture_orig_height / bh + + elif self.look == "horizontal": + if self.border_type == "horizontal": + bw = self.picture_orig_width / (self.border_width - self.border_x) + self.picture_tmp_width = self.picture_orig_width / bw - crop_x + + bh = self.picture_orig_height / (self.border_height - self.border_y) + self.picture_tmp_height = self.picture_orig_height / bh + + elif self.border_type == "vertical": + bw = self.picture_orig_width / (self.border_width - self.border_x) + self.picture_tmp_width = self.picture_orig_width / bw - crop_x + + bh = self.picture_orig_height / (self.border_height - self.border_y) + self.picture_tmp_height = self.picture_orig_height / bh + + + if self.picture_tmp_width > self.picture_tmp_height: + self.picture_view_width = 586.66 + m = self.picture_tmp_width / 586.66 + self.picture_view_height = self.picture_tmp_height/m + if self.picture_tmp_height > self.picture_tmp_width: + self.picture_view_height = 586.66 + m = self.picture_tmp_height / 586.66 + self.picture_view_width = self.picture_tmp_width/m + + # Zapamiętanie rozmiaru obrazka dla kontrolki + self.orig_ratio_width = self.picture_view_width + self.orig_ratio_height = self.picture_view_height + + def on_menu_file_load_img_generic(self, widget): + global grid, file_img_selected + + filename=FileChooserIMGLoad() + + if len(file_img_selected) != 0: + + self.pixbuf_orig = GdkPixbuf.Pixbuf.new_from_file(filename=file_img_selected) + + self.set_ratio_picture_view() + self.pixbuf_view = self.pixbuf_orig.scale_simple(self.picture_view_width, self.picture_view_height, GdkPixbuf.InterpType.HYPER) + + if self.picture_view_width > self.picture_view_height: + self.horizontal = True + self.vertical = False + self.resize(582.66,413.34) + self.look = "horizontal" + self.border_type = "horizontal" + elif self.picture_view_height > self.picture_view_width: + self.vertical = True + self.horizontal = False + self.resize(413.34,582.66) + self.look = "vertical" + self.border_type = "vertical" + else: + self.horizontal = False + self.vertical = False + + + self.set_ratio_border_size() + + + + self.border_visible = True + + # nie rysujemy na orginale ale na kopii z okna + self.drawing_area.set_size_request(self.pixbuf_view.get_width(), self.pixbuf_view.get_height()) + self.drawing_area.set_events(Gdk.EventMask.ALL_EVENTS_MASK) + + self.show_all() + + def add_edit_menu_actions(self, action_group): + action_info_menu = Gtk.Action(name="EditMenu", label="Edit") + action_group.add_action(action_info_menu) + + action_new = Gtk.Action( + name="Rotate", + label="Frame rotation", + tooltip="Rotate border", + ) + action_new.connect("activate", self.on_menu_rotate) + action_group.add_action_with_accel(action_new, None) + + + def add_info_menu_actions(self, action_group): + action_info_menu = Gtk.Action(name="InfoMenu", label="Info") + action_group.add_action(action_info_menu) + + action_new = Gtk.Action( + name="Help", + label="Help", + tooltip="Help", + ) + action_new.connect("activate", self.on_menu_help) + action_group.add_action_with_accel(action_new, None) + + action_new = Gtk.Action( + name="About", + label="About", + tooltip="About", + ) + action_new.connect("activate", self.on_menu_about) + action_group.add_action_with_accel(action_new, None) + + action_new = Gtk.Action( + name="License", + label="License", + tooltip="License", + ) + action_new.connect("activate", self.on_menu_license) + action_group.add_action_with_accel(action_new, None) + + + + def add_file_menu_actions(self, action_group): + action_filemenu = Gtk.Action(name="FileMenu", label="File") + action_group.add_action(action_filemenu) + + """ + # sposób dodawania podmenu + action_fileloadmenu = Gtk.Action(name="FileLoad", stock_id=Gtk.STOCK_OPEN) + action_group.add_action(action_fileloadmenu) + + action_new = Gtk.Action( + name="LoadImg", + label="Wczytaj Obrazek", + tooltip="Wczytuje obrazek", + ) + action_new.connect("activate", self.on_menu_file_load_img_generic) + action_group.add_action_with_accel(action_new, None) + """ + + action_fileload = Gtk.Action(name="FileLoad", stock_id=Gtk.STOCK_OPEN) + action_fileload.connect("activate", self.on_menu_file_load_img_generic) + action_group.add_action(action_fileload) + + action_filesave = Gtk.Action(name="FileSave", stock_id=Gtk.STOCK_SAVE) + action_filesave.connect("activate", self.on_menu_file_save_img) + action_group.add_action(action_filesave) + + + action_print = Gtk.Action(name="FilePrint", stock_id=Gtk.STOCK_PRINT) + action_print.connect("activate", self.print_image) + action_group.add_action(action_print) + + + action_filequit = Gtk.Action(name="FileQuit", stock_id=Gtk.STOCK_QUIT) + action_filequit.connect("activate", self.on_menu_file_quit) + action_group.add_action(action_filequit) + + + + # tworzy menu bar + def create_ui_manager(self): + uimanager = Gtk.UIManager() + + # Throws exception if something went wrong + uimanager.add_ui_from_string(UI_INFO) + + # Add the accelerator group to the toplevel window + accelgroup = uimanager.get_accel_group() + self.add_accel_group(accelgroup) + return uimanager + + def on_menu_about(self, widget): + dialog = DialogAbout(self) + response = dialog.run() + + dialog.destroy() + + def on_menu_license(self, widget): + dialog = DialogLicense(self) + response = dialog.run() + + dialog.destroy() + + + def on_menu_help(self, widget): + dialog = DialogHelp(self) + response = dialog.run() + + dialog.destroy() + + def on_menu_rotate(self, widget): + global rotate + + + if self.border_type == "horizontal": + self.border_type = "vertical" + self.horizontal = False + self.vertical = True + + single = self.picture_view_width*0.3 + self.border_width = single + self.border_height = single*1.4 + self.border_x = 0 + self.border_y = 0 + + rotate = True + + elif self.border_type == "vertical": + self.border_type = "horizontal" + self.horizontal = True + self.vertical = False + + single = self.picture_view_height*0.3 + self.border_height = single + self.border_width = single*1.4 + self.border_x = 0 + self.border_y = 0 + + rotate = True + else: + pass + + print ("ASPECT: "+self.border_type) + print ("BORDER-WIDTH :"+str(self.border_width)) + print ("BORDER-HEIGHT:"+str(self.border_height)) + + self.drawing_area.queue_draw() + + def on_menu_file_save_img(self, widget): + global file_img_selected + + if self.pixbuf_tmp != None: + filename=FileChooserIMGSave() + if len(file_img_selected) != 0: + self.pixbuf_view.savev(file_img_selected, "jpeg", ["quality"], ["100"]) + else: + dialog = DialogCropWarning(self) + response = dialog.run() + + dialog.destroy() + + def on_menu_file_quit(self, widget): + Gtk.main_quit() + + def print_page(self, operation=None, context=None, page_nr=None): + + ctx = context.get_cairo_context() + + # make cairo ImageSurface from the png file + surface = cairo.ImageSurface.create_from_png('/tmp/photocrop.png') + #ctx.rectangle(50,50,100,100) + ctx.set_source_surface(surface) + ctx.paint () + os.remove("/tmp/photocrop.png"); + + + def print_image(self, widget): + + if self.pixbuf_tmp == None: + self.pixbuf_tmp = self.pixbuf_orig + + + # źle obraca + #if self.border_type == "horizontal": + # self.pixbuf_tmp.rotate_simple(GdkPixbuf.PixbufRotation.COUNTERCLOCKWISE) + # #pixbuf2.rotate_simple(GdkPixbuf.PixbufRotation.CLOCKWISE) + # self.border_type = "vertical" + + FACTOR_MM_TO_PIXEL = 2.834645669 + + + if self.format_size == "10x15": + #if self.horizontal == True and self.vertical == False: + if self.border_type == "horizontal": + page_width = 148 + page_height = 104.99 + + img_height =104.99 * FACTOR_MM_TO_PIXEL + img_width = 148 * FACTOR_MM_TO_PIXEL + #elif self.horizontal == False and self.vertical == True: + elif self.border_type == "vertical": + + page_width = 104.99 + page_height = 148 + + img_width =104.99 * FACTOR_MM_TO_PIXEL + img_height = 148 * FACTOR_MM_TO_PIXEL + + size = "10x15" + elif self.format_size == "13x18": + #if self.horizontal == True and self.vertical == False: + if self.border_type == "horizontal": + + page_width = 178 + page_height = 127 + + img_height = 127 * FACTOR_MM_TO_PIXEL + img_width = 178 * FACTOR_MM_TO_PIXEL + #elif self.horizontal == False and self.vertical == True: + elif self.border_type == "vertical": + + page_width = 127 + page_height = 178 + + img_width = 127 * FACTOR_MM_TO_PIXEL + img_height = 178 * FACTOR_MM_TO_PIXEL + size = "5x7" + elif self.format_size == "A4": + #if self.horizontal == True and self.vertical == False: + if self.border_type == "horizontal": + page_width = 297 + page_height = 207 + + img_height = 207 * FACTOR_MM_TO_PIXEL + img_width = 297 * FACTOR_MM_TO_PIXEL + #elif self.horizontal == False and self.vertical == True: + elif self.border_type == "vertical": + + page_width = 207 + page_height = 297 + + img_width = 207 * FACTOR_MM_TO_PIXEL + img_height = 297 * FACTOR_MM_TO_PIXEL + + size = "A4" + + dpi = 600 + + # z orginalnymi wielkościami nie chce drukowac + pixbuf2 = self.pixbuf_tmp.scale_simple(img_width, img_height, GdkPixbuf.InterpType.HYPER) + + pixbuf2.savev("/tmp/photocrop.png","png", ["quailty"], ["100"]) + + #ps = Gtk.PaperSize.new_custom(size, size, self.pixbuf_tmp.get_width(), self.pixbuf_tmp.get_height(), Gtk.Unit.POINTS) + ps = Gtk.PaperSize.new_custom(size, size, page_width, page_height, Gtk.Unit.MM) + + print_settings = Gtk.PrintSettings() + print_settings.set_resolution(dpi) + + page_setup = Gtk.PageSetup() + page_setup.set_paper_size(ps) + page_setup.set_bottom_margin(0.0, Gtk.Unit.MM) + page_setup.set_left_margin(0.0, Gtk.Unit.MM) + page_setup.set_right_margin(0.0, Gtk.Unit.MM) + page_setup.set_top_margin(0.0, Gtk.Unit.MM) + + #if self.border_type == "horizontal": + # page_setup.set_orientation(Gtk.PageOrientation.LANDSCAPE) + #elif self.border_type == "vertical": + # page_setup.set_orientation(Gtk.PageOrientation.PORTRAIT) + + + print_operation = Gtk.PrintOperation() + print_operation.set_unit(Gtk.Unit.POINTS) + print_operation.set_n_pages(1) + print_operation.set_default_page_setup(page_setup) + print_operation.set_print_settings(print_settings) + print_operation.connect("draw_page", self.print_page) + #print_operation.set_export_filename("example.pdf") + + result = print_operation.run(Gtk.PrintOperationAction.PRINT_DIALOG, None) # window zamisat None + + #result = print_operation.run(Gtk.PrintOperationAction.PREVIEW, None) + print(result) + + # przycinamy ! + def photo_crop(self, button): + + if self.border_x < 0: + dialog = DialogWarning(self) + response = dialog.run() + dialog.destroy() + return + if self.border_y < 0: + dialog = DialogWarning(self) + response = dialog.run() + dialog.destroy() + return + if self.border_width > self.picture_view_width: + dialog = DialogWarning(self) + response = dialog.run() + dialog.destroy() + return + # FIXME - w sumie to jest zastanawiające !? + if self.border_height + self.border_y > self.picture_view_height: + dialog = DialogWarning(self) + response = dialog.run() + dialog.destroy() + return + + + if self.border_x != 0 : + bx = self.picture_view_width / self.border_x + crop_x = self.picture_orig_width / bx + else: + crop_x = 0 + + if self.border_y != 0: + by = self.picture_view_height / self.border_y + crop_y = self.picture_orig_height / by + else: + crop_y = 0 + + bw = self.picture_view_width / self.border_width + crop_width = self.picture_orig_width / bw - crop_x + + bh = self.picture_view_height / self.border_height + crop_height = self.picture_orig_height / bh + + + # False - kanał Alpha + self.pixbuf_tmp = GdkPixbuf.Pixbuf.new(GdkPixbuf.Colorspace.RGB, False, 8, crop_width, crop_height) + + # zera na koncu to dest_x i dest_y + self.pixbuf_orig.copy_area(crop_x, crop_y, crop_width, crop_height, self.pixbuf_tmp, 0, 0) + + if rotate == False: + + self.picture_tmp_width = float(self.pixbuf_tmp.get_width()) + self.picture_tmp_height = float(self.pixbuf_tmp.get_height()) + + # tym razem przeliczamy z uwzględnieniem bufora tymczasowego + if self.picture_tmp_width > self.picture_tmp_height: + self.picture_view_width = 586.66 + m = self.picture_tmp_width / 586.66 + self.picture_view_height = self.picture_tmp_height/m + if self.picture_tmp_height > self.picture_tmp_width: + self.picture_view_height = 586.66 + m = self.picture_tmp_height / 586.66 + self.picture_view_width = self.picture_tmp_width/m + + + + else: + self.set_ratio_picture_view_after_rotation() + + self.drawing_area.set_size_request(self.picture_view_width, self.picture_view_height) + self.drawing_area.set_events(Gdk.EventMask.ALL_EVENTS_MASK) + + self.pixbuf_view = self.pixbuf_tmp.scale_simple(self.picture_view_width, self.picture_view_height, GdkPixbuf.InterpType.HYPER) + + self.picture_view_x = 0 + self.picture_view_y = 0 + + self.border_visible = False + + self.drawing_area.queue_draw() + + # przywracamy + def photo_restore(self, button): + + self.border_visible = True + + self.set_ratio_picture_view() + self.pixbuf_view = self.pixbuf_orig.scale_simple(self.orig_ratio_width, self.orig_ratio_height, GdkPixbuf.InterpType.BILINEAR) + + self.drawing_area.set_size_request(self.orig_ratio_width, self.orig_ratio_height) + self.drawing_area.set_events(Gdk.EventMask.ALL_EVENTS_MASK) + self.pixbuf_tmp = None # uniemożliwiamy zapis + self.show_all() + + self.drawing_area.queue_draw() + + + def on_format_combo_changed(self, combo): + tree_iter = combo.get_active_iter() + if tree_iter is not None: + model = combo.get_model() + self.format_size = model[tree_iter][0] + print("Selected: format=%s" % self.format_size) + + self.set_ratio_border_size() + + self.drawing_area.queue_draw() + + def on_scroll(self, widget, event): + """ handles on scroll event""" + # Handles zoom in / zoom out on Ctrl+mouse wheel + accel_mask = Gtk.accelerator_get_default_mod_mask() + if event.state & accel_mask == Gdk.ModifierType.CONTROL_MASK: + direction = event.get_scroll_deltas()[2] + + if direction > 0: + scrolling = "zoom_out" + else: + scrolling = "zoom_in" + + self.border_height += self.border_properties[self.format_size][self.border_type][scrolling]["height"] + self.border_width += self.border_properties[self.format_size][self.border_type][scrolling]["width"] + """ + # tu jest jakiś błąd + if self.border_width > self.picture_view_width: + self.border_width -= 1 + if self.border_height+self.border_y > self.picture_view_height: + self.border_height -= 1 + """ + self.drawing_area.queue_draw() + + def unclick_in_drawing_area (self, box, event): + self.button_press = False + print ("Przycisk myszki puszczony") + + + def onclick_in_drawing_area (self, box, event): + if event.button == 1: + self.button_press = True + print ("Lewy przyciski myszki naciśnięty") + + def on_mouse_move_in_drawing_area(self, box, event): + + + if self.button_press == True: + + if self.border_type == "vertical": + + #print ("VERTICAL %%") + + if self.last_x < event.x: + self.border_x += 1 + self.border_width += 1 + if event.x < self.last_x: + self.border_x -= 1 + self.border_width -= 1 + if self.last_y < event.y: + self.border_y += 1 + self.border_height += 0.0 + if event.y < self.last_y: + self.border_y -= 1 + self.border_height -= 0.0 + + elif self.border_type == "horizontal": + #print ("Horizontal %%") + if self.last_x < event.x: + self.border_x += 1 + self.border_width += 1 + if event.x < self.last_x: + self.border_x -= 1. + self.border_width -= 1 + if self.last_y < event.y: + self.border_y += 1 + self.border_height += 0.0 + if event.y < self.last_y: + self.border_y -= 1 + self.border_height -= 0.0 + + self.last_y = event.y + self.last_x = event.x + """ + # jeśli będzie się napierać na skraj krawędzi wówczas powiększa ramkę + if self.border_x < 0: + self.border_x += 1 + self.border_width += 1 + if self.border_y < 0: + self.border_y += 1 + self.border_height +=1 + # tu jest jakiś błąd + + # powoduje błędne zachowanie ramki + if self.border_type == "vertical": + if self.border_width > self.picture_view_width: + self.border_width -= 1 + self.border_x -= 1 + if self.border_height+self.border_y > self.picture_view_height: + self.border_height -= 1 + self.border_y -= 1 + elif self.border_type == "horizontal": + if self.border_height+self.border_y> self.picture_view_width: + self.border_width -= 1 + self.border_x -= 1 + if self.border_width > self.picture_view_height: + self.border_height -= 1 + self.border_y -= 1 + """ + + self.drawing_area.queue_draw() + + def init_ui(self): + # JPG akceptuje jedynie z GIMPa + self.border_properties = { "10x15" : { "horizontal" : { "zoom_out" : {"width" : -1.48, "height" : -0.92}, "zoom_in" : {"width" : 1.48, "height" : 0.92}}, + "vertical" : { "zoom_out": { "width" : -0.92, "height" : -1.48}, "zoom_in": { "width" : 0.92, "height" : 1.48}}, + "square" : { "zoom_out" : { "width" : -1, "height" : -1}, "zoom_out" : { "width" : 1, "height" : 1}}}, + + "13x18" : { "horizontal" : { "zoom_out" : {"width" : -1.82, "height" : -1.30}, "zoom_in" : {"width" : 1.82, "height" : 1.30}}, + "vertical" : { "zoom_out": { "width" : -1.30, "height" : -1.78}, "zoom_in": { "width" : 1.30, "height" : 1.78}}, + "square" : { "zoom_out" : { "width" : -1, "height" : -1}, "zoom_out" : { "width" : 1, "height" : 1}}}, + + "A4" : { "horizontal" : { "zoom_out" : {"width" : -2.97, "height" : -1.84}, "zoom_in" : {"width" : 2.97, "height" : 1.84}}, + "vertical" : { "zoom_out": { "width" : -1.84, "height" : -2.97}, "zoom_in": { "width" : 1.84, "height" : 2.97}}, + "square" : { "zoom_out" : { "width" : -1, "height" : -1}, "zoom_out" : { "width" : 1, "height" : 1}}}} + + + #self.props.border_width = 20 + self.add(grid) + self.pixbuf_tmp = None + grid.set_row_spacing(10) + grid.set_column_spacing(10) + grid.set_column_homogeneous(True) # rozszerza kontrolki na resztę okna + + action_group = Gtk.ActionGroup(name="my_actions") + + self.add_file_menu_actions(action_group) + self.add_edit_menu_actions(action_group) + self.add_info_menu_actions(action_group) + + uimanager = self.create_ui_manager() + uimanager.insert_action_group(action_group) + + menubar = uimanager.get_widget("/MenuBar") + box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) + box.pack_start(menubar, False, False, 0) + + grid.attach(box, 0, 0, 3, 1) + + + file_img_selected=get_resource_path("/usr/share/photocrop/IMG_6854.JPG") #img/blank.png + self.pixbuf_orig = GdkPixbuf.Pixbuf.new_from_file(filename=file_img_selected) + + self.format_size = "10x15" + self.set_ratio_picture_view() + self.pixbuf_view = self.pixbuf_orig.scale_simple(self.picture_view_width, self.picture_view_height, GdkPixbuf.InterpType.HYPER) + + self.border_visible = True + + if self.picture_view_width > self.picture_view_height: + self.horizontal = True + self.vertical = False + self.look = "horizontal" + self.border_type = "horizontal" + elif self.picture_view_height > self.picture_view_width: + self.vertical = True + self.horizontal = False + self.look = "vertical" + self.border_type = "vertical" + else: + self.horizontal = False + self.vertical = False + self.look = "square" + + self.drawing_area = Gtk.DrawingArea() + + self.drawing_area.set_size_request(self.pixbuf_view.get_width(), self.pixbuf_view.get_height()) + self.drawing_area.set_events(Gdk.EventMask.ALL_EVENTS_MASK) + + self.drawing_area.connect("draw", self.on_drawing_area_draw) + + frame = Gtk.Frame() + event_box = Gtk.EventBox () + self.last_x = 1 + self.last_y = 1 + self.border_x = 0 + self.border_y = 0 + self.button_press = False + self.pixbuf_tmp = None + event_box.connect ('button-press-event', self.onclick_in_drawing_area) + event_box.connect ('button-release-event', self.unclick_in_drawing_area) + event_box.connect("motion-notify-event", self.on_mouse_move_in_drawing_area) + event_box.add_events(Gdk.EventMask.POINTER_MOTION_MASK | Gdk.EventMask.BUTTON_PRESS_MASK) + + event_box.add(self.drawing_area) + frame.add(event_box) + grid.attach(frame,0,1,3,1) + + button1 = Gtk.Button.new_with_label("Crop") + button1.connect("clicked", self.photo_crop) + grid.attach(button1,0,4,1,1) + + button2 = Gtk.Button.new_with_label("Restore") + button2.connect("clicked", self.photo_restore) + grid.attach(button2,1,4,1,1) + + format_store = Gtk.ListStore(str) + format_photo = [ + "10x15", + "13x18", + "A4", + ] + for fp in format_photo: + format_store.append([fp]) + + format_combo = Gtk.ComboBox.new_with_model(format_store) + format_combo.connect("changed", self.on_format_combo_changed) + renderer_text = Gtk.CellRendererText() + format_combo.pack_start(renderer_text, True) + format_combo.add_attribute(renderer_text, "text", 0) + format_combo.set_active(0) + grid.attach(format_combo,2,4,1,1) + + self.drawing_area.connect('scroll-event', self.on_scroll) + + self.set_border_width(10) + self.set_title("Photo Crop (alpha)") + #self.set_default_size(700, 600) + #self.resize(700, 600) + self.set_resizable(False) + self.connect("destroy", Gtk.main_quit) + + + +win = MyWindow() +win.show_all() +Gtk.main()