#!/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 = """ """ """ # szkielet z podmenu """ 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()