diff options
-rw-r--r-- | DEBIAN/HOWTO | 2 | ||||
-rw-r--r-- | DEBIAN/debian.changelog | 5 | ||||
-rw-r--r-- | DEBIAN/debian.control | 13 | ||||
-rw-r--r-- | DEBIAN/debian.rules | 29 | ||||
-rw-r--r-- | DEBIAN/format.sh | 1 | ||||
-rw-r--r-- | DEBIAN/photocrop.dsc | 41 | ||||
-rw-r--r-- | INSTALL | 92 | ||||
-rw-r--r-- | LICENSE | 339 | ||||
-rw-r--r-- | Makefile | 21 | ||||
-rw-r--r-- | Makefile.in.gz | bin | 0 -> 247 bytes | |||
-rw-r--r-- | RPM/photocrop.spec | 71 | ||||
-rw-r--r-- | bugs.txt | 3 | ||||
-rw-r--r-- | changelog | 70 | ||||
-rw-r--r-- | configure.gz | bin | 0 -> 495 bytes | |||
-rw-r--r-- | data/IMG_6854.JPG | bin | 0 -> 359172 bytes | |||
-rw-r--r-- | data/clip.png | bin | 0 -> 55258 bytes | |||
-rw-r--r-- | data/photocrop.desktop | 15 | ||||
-rw-r--r-- | src/photocrop.py | 1164 | ||||
-rw-r--r-- | xcf/clip.xcf | bin | 0 -> 51253 bytes |
19 files changed, 1866 insertions, 0 deletions
diff --git a/DEBIAN/HOWTO b/DEBIAN/HOWTO new file mode 100644 index 0000000..a371e0b --- /dev/null +++ b/DEBIAN/HOWTO @@ -0,0 +1,2 @@ +foramt zapisu nazwy pliku: + photocrop_0.221225-0~alpha.tar.gz diff --git a/DEBIAN/debian.changelog b/DEBIAN/debian.changelog new file mode 100644 index 0000000..0adf1f3 --- /dev/null +++ b/DEBIAN/debian.changelog @@ -0,0 +1,5 @@ +photocrop (0.221225-4) unstable; urgency=low + + * Last release + + -- Przemysław R. Pietraszczyk Sat, 25 Dec 2022 08:31:41 +0200 diff --git a/DEBIAN/debian.control b/DEBIAN/debian.control new file mode 100644 index 0000000..bf96b7d --- /dev/null +++ b/DEBIAN/debian.control @@ -0,0 +1,13 @@ +Source: photocrop +Section: python +Priority: extra +Maintainer: Przemysław R. Pietraszczyk +Build-Depends: debhelper-compat (= 13), python3-all, dh-python, python3-gi, python3-gi-cairo, gir1.2-gtk-3.0, fakeroot +Standards-Version: 0.230112-0~alpha +Homepage: http://prymula.ct8.pl + + +Package: photocrop +Architecture: all +Depends: ${misc:Depends}, python3-all, python3-gi, python3-gi-cairo, gir1.2-gtk-3.0 +Description: An application for cropping photos to popular paper sizes. diff --git a/DEBIAN/debian.rules b/DEBIAN/debian.rules new file mode 100644 index 0000000..ce6541d --- /dev/null +++ b/DEBIAN/debian.rules @@ -0,0 +1,29 @@ +#!/usr/bin/make -f + +export DH_VERBOSE = 1 +#export PYBUILD_NAME = photocrop +#export PYBUILD_SYSTEM = custom + +clean: + @ + +build: + @ + +binary: + mkdir -pm 0755 debian/photocrop + mkdir -pm 0755 debian/photocrop/usr/bin + mkdir -pm 0755 debian/photocrop/usr/share + mkdir -pm 0755 debian/photocrop/usr/share/photocrop + mkdir -pm 0755 debian/photocrop/usr/share/applications + cp src/photocrop.py debian/photocrop/usr/bin + cp data/clip.png debian/photocrop/usr/share/photocrop + cp data/IMG_6854.JPG debian/photocrop/usr/share/photocrop + cp data/photocrop.desktop debian/photocrop/usr/share/applications + dh_gencontrol + dh_builddeb +# dh $@ --with python3 --buildsystem=pybuild +# dh $@ --with python3 + +#override_dh_auto_configure: +# dh_auto_configure -- diff --git a/DEBIAN/format.sh b/DEBIAN/format.sh new file mode 100644 index 0000000..d0e6a06 --- /dev/null +++ b/DEBIAN/format.sh @@ -0,0 +1 @@ +exec /usr/lib/build/debtransform ./ ./photocrop.dsc ./exec diff --git a/DEBIAN/photocrop.dsc b/DEBIAN/photocrop.dsc new file mode 100644 index 0000000..a742dc5 --- /dev/null +++ b/DEBIAN/photocrop.dsc @@ -0,0 +1,41 @@ +-----BEGIN PGP SIGNED MESSAGE----- +Hash: SHA256 + +Format: 1.0 +Source: photocrop +Binary: photocrop +Architecture: all +Version: 0.230112-0~alpha +Maintainer: Przemysław R. Pietraszczyk <przem@pietraszczyk.vxm.pl> +Homepage: http://pietraszczyk.vxm.pl +DEBTRANSFORM-TAR: debian.tar.gz +DEBTRANSFORM-TAR: photocrop_0.2301012-0~alpha.tar.gz + +Standards-Version: 0.2301012-0~alpha +Build-Depends: debhelper-compat (= 13), python3-all, dh-python, python3-gi, python3-gi-cairo, gir1.2-gtk-3.0, fakeroot +Package-List: + photocrop deb x11 optional arch=all +Files: + b31649bc23b2b7bca9ab70ea3410711a 128820 photocrop_0.230112-0~alpha.tar.gz + 29e7e7e60bc81891e3da3871b9eeb549 764 photocrop-0.230112-0~alpha.debian.tar.xz + +-----BEGIN PGP SIGNATURE----- + +mQENBGEf/c4BCAC2d4ymW0pRZV36qLtlt/WGb83kos5UX5UbwvkQrbUjAbOPOY8w +DT3M1neYOAPZx38924aPTFKbZPcz+rK/7Wcv1kzgfux5zXQJTLeqpkhUYAgXUg2p +oK9ZXsai82fOicTrClOyJLLYQ8C1vj8yUh7e3ERljEyp5Nxg/lY92rwcZ4WYR193 +nGDInlDl5JlWUcLlk/RFnC5bB+T6ZZr5FBX/eDnKAPEl+N3MWpDs2JLDy7EUPhcG +U/60X0wuXHPTwMoNbB3ep/bWRxwEej0sFad5GXeCh7hKCroi/kLmLTDIxSD8lsRr +Y4H/8H2lBBsQq7bRL88N6ZDGCocPo11V83kFABEBAAG0NmhvbWU6cHJ6ZW0gT0JT +IFByb2plY3QgPGhvbWU6cHJ6ZW1AYnVpbGQub3BlbnN1c2Uub3JnPokBPgQTAQgA +KAUCYR/9zgIbAwUJBB6wAAYLCQgHAwIGFQgCCQoLBBYCAwECHgECF4AACgkQcXEc +NPcNefFEAAf+Kg4cs/C99kEIMv/PO85VW+p8rcTwCViOFUX5WrBhwsRyPAKrJPPG +KD6PdnvoplcNQwhQ8nRsRiiaiUtPcj8Bvi6EdPgSgXXObKKJtCyaAa1rURdlb9iW +CfvXA6oW+PGlii9BMnXOAtkeFIzZooO9oXd+wez66P+4VWFiFzxanLfLn/hwbWxQ +68rlO3QNGbrMeODBgwh9s83XGmAg47mn2fldTAmTbJDf9tMi1LhX2MmLyN9wjqsd +4IZ9JMri2JTnIhYfxWdKT9gsu7q0g8LqonaXMvlOEyHFRF1YQ0i7G6fFbvDcKCZN +W1Eja55FdN7smv5Eck6UTIIYyWPuAv45uohGBBMRAgAGBQJhH/3PAAoJEDswEbdr +nWUj4M0AniJ389dyvUjjgS91AcOb08E4moV9AJ9WDL3/7GYYUL/Azw43QucWPnXr +uw== +=+lfH +-----END PGP SIGNATURE----- @@ -0,0 +1,92 @@ +Windows + +Go to http://www.msys2.org/ and download the x86_64 installer + +Follow the instructions on the page for setting up the basic environment + +Run C:\msys64\mingw64.exe - a terminal window should pop up + +Execute pacman -Suy + +Execute pacman -S mingw-w64-x86_64-gtk3 mingw-w64-x86_64-python3 mingw-w64-x86_64-python3-gobject + + +Ubuntu/Debian + +Installing the system provided PyGObject: +Open a terminal + +Execute sudo apt install python3-gi python3-gi-cairo gir1.2-gtk-3.0 + +Installing from PyPI with pip: +Open a terminal and enter your virtual environment + +Execute sudo apt install libgirepository1.0-dev gcc libcairo2-dev pkg-config python3-dev gir1.2-gtk-3.0 to install the build dependencies and GTK + +Execute pip3 install pycairo to build and install Pycairo + +Execute pip3 install PyGObject to build and install PyGObject + + + +Fedora + +Installing the system provided PyGObject: +Open a terminal + +Execute sudo dnf install python3-gobject gtk3 + +Open a terminal and enter your virtual environment + +Execute sudo dnf install gcc gobject-introspection-devel cairo-gobject-devel pkg-config python3-devel gtk3 to install the build dependencies and GTK + +Execute pip3 install pycairo to build and install Pycairo + +Execute pip3 install PyGObject to build and install PyGObject + + +Arch Linux + +Installing the system provided PyGObject: +Open a terminal + +Execute sudo pacman -S python-gobject gtk3 + +Installing from PyPI with pip: +Open a terminal and enter your virtual environment + +Execute sudo pacman -S python cairo pkgconf gobject-introspection gtk3 to install the build dependencies and GTK + +Execute pip3 install pycairo to build and install Pycairo + +Execute pip3 install PyGObject to build and install PyGObject + + + + +openSUSE + +Installing the system provided PyGObject: +Open a terminal + +Execute sudo zypper install python3-gobject python3-gobject-Gdk typelib-1_0-Gtk-3_0 libgtk-3-0 + +Installing from PyPI with pip: +Open a terminal and enter your virtual environment + +Execute sudo zypper install cairo-devel pkg-config python3-devel gcc gobject-introspection-devel to install the build dependencies and GTK + +Execute pip3 install pycairo to build and install Pycairo + +Execute pip3 install PyGObject to build and install PyGObject + + + + +macOS + +Go to https://brew.sh/ and install homebrew + +Open a terminal + +Execute brew install pygobject3 gtk+3 @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..3f36b99 --- /dev/null +++ b/Makefile @@ -0,0 +1,21 @@ + +prefix=/usr + +all: + +install: + mkdir -pm 0755 $(prefix)/share/photocrop + install -m 0755 src/photocrop.py $(prefix)/bin + install -m 0644 data/clip.png $(prefix)/share/photocrop + install -m 0644 data/IMG_6854.JPG $(prefix)/share/photocrop + install -m 0644 data/photocrop.desktop $(prefix)/share/applications + + +uninstall: + rm $(prefix)/share/photocrop/clip.png + rm $(prefix)/share/photocrop/IMG_6854.JPG + rmdir $(prefix)/share/photocrop/ + rm $(prefix)/bin/photocrop.py + rm $(prefix)/share/applications/photocrop.desktop + +.PHONY: all install uninstall diff --git a/Makefile.in.gz b/Makefile.in.gz Binary files differnew file mode 100644 index 0000000..457147f --- /dev/null +++ b/Makefile.in.gz diff --git a/RPM/photocrop.spec b/RPM/photocrop.spec new file mode 100644 index 0000000..228be57 --- /dev/null +++ b/RPM/photocrop.spec @@ -0,0 +1,71 @@ +# +# spec file for package photocrop +# +# Copyright (c) 2020 SUSE LLC +# +# All modifications and additions to the file contributed by third parties +# remain the property of their copyright owners, unless otherwise agreed +# upon. The license for this file, and modifications and additions to the +# file, is the same license as for the pristine package itself (unless the +# license for the pristine package is not an Open Source License, in which +# case the license is the MIT License). An "Open Source License" is a +# license that conforms to the Open Source Definition (Version 1.9) +# published by the Open Source Initiative. + +# Please submit bugfixes or comments via https://bugs.opensuse.org/ +# + +%define unmangled_version 0.230112-0~alpha +Name: photocrop +Version: 0.230112 +Release: 0~alpha +Summary: An application for cropping photos to popular paper sizes. +License: GPL +URL: https://pietraszczyk.vxm.pl/przycinanie-zdjec/ +Source0: %{name}-%{unmangled_version}.tar.gz +%if 0%{?suse_version}>=150000 +BuildRequires: python3, python3-gobject, python3-gobject-Gdk, typelib-1_0-Gtk-3_0, libgtk-3-0 +Requires: python3, python3-gobject, python3-gobject-Gdk, typelib-1_0-Gtk-3_0, libgtk-3-0 +%endif +%if 0%{?fedora}>=35 +BuildRequires: python3, python3-gobject, gtk3 +Requires: python3, python3-gobject, gtk3 +%endif +BuildArch: noarch + +%description + + +%prep +%setup -n %{name}-%{unmangled_version} -n %{name}-%{unmangled_version} + +%build + +%install + +mkdir -p %{buildroot}/usr +mkdir -p %{buildroot}/usr/share +mkdir -p %{buildroot}/usr/share/photocrop +mkdir -p %{buildroot}/usr/share/applications +mkdir -p %{buildroot}/usr/bin + +install -m 0755 src/photocrop.py %{buildroot}/usr/bin +install -m 0644 data/clip.png %{buildroot}/usr/share/photocrop/clip.png +#install -m 0644 data/blank.png %{buildroot}/usr/share/photocrop/blank.png +install -m 0644 data/IMG_6854.JPG %{buildroot}/usr/share/photocrop/IMG_6854.JPG +install -m 0644 data/photocrop.desktop %{buildroot}/usr/share/applications + + + +%files +%defattr(0755,root,root) +/usr/bin/photocrop.py +/usr/share/photocrop/ +%defattr(0644,root,root) +/usr/share/photocrop/clip.png +#/usr/share/photocrop/blank.png +/usr/share/photocrop/IMG_6854.JPG +/usr/share/applications/photocrop.desktop + +%changelog + diff --git a/bugs.txt b/bugs.txt new file mode 100644 index 0000000..0a6128d --- /dev/null +++ b/bugs.txt @@ -0,0 +1,3 @@ +1. Losowe zniekształcenia na podglądzie po przycięciu, ale tylko na podglądzie, wydruk jest prawidłowy. +2. Źle współpracuje z grafiką utworzoną w Krita. +3. Przed wydrukiem należy spojrzeć w kreatorze wydruku na sugerowaną orientację zdjęcia. diff --git a/changelog b/changelog new file mode 100644 index 0000000..9d9b626 --- /dev/null +++ b/changelog @@ -0,0 +1,70 @@ +0.230112-0 - Poprawki odświeżania okna po przycięciu +0.230107-0 - Poprawiłem skalowanie dla średniego formatu. Wyszła na jaw zła współpraca z grafiką utworzoną w Krita ! +0.221229-0 - Interfejs po angielsku, poprawiłem skalowanie ramki dla małego i dużego formatu. +0.221225-0 - Korekta wielkości początkowej ramki +0.221224-3 - Poprawki dla konfiguracji ramki dla pozostałych formatów +0.221234-2 - Poprawiłem skalowanie dla zdjęć horyzontalnych +0.221224-1 - W zależności jaka była pierwotnie orientacja zdjęcia, po obrocie jest ono odpowiednio przycinane +0.221224-0 - Nie rozciąga już zdjęcia po przycięciu po obrocie na wertylkane +0.221223-0 - Poprawiłem odzyskiwanie ramki po obrocie, dodałem zapis przyciętej fotografii +0.221214-3 - Zrezygnowałem z ograniczeń ramki przy krawędziach zdjęcia gdyż źle oddziaływały na ramkę. Przywróciłem sposób z wyświetlaniem okna dialogowego po przekroczeniu krawędzi. +0.221214-2 - Poprawki drobnych błędów +0.221214-1 - Zwiększyłem rozmiar ramki po obrocie +0.221214-0 - Poprawiłem błąd powodujący wyłączenie się skryptu po przycięciu obrazka w dolnych partiach +0.221213-2 - Dodałem menu wraz z odnośnikiem z licencją (w końcu!). Poprawiłem informacje "O Programie" +0.221213-1 - Poprawki błędów związanych z literówkami dotyczącymi aspektu ramki +0.221213-0 - Poprawiłem odświeżanie kontrolki po obrocie - jednak dla obrazków wertykalnych zbyt niskie położenie ramki grozi krachem aplikacji +0.221212-1 - Poprawiłem przekształcanie ramki po obrocie +0.221212-0 - Okno zmienia już swoją wielkość po rotacji, lepsze dobór ramki po rotacji obrazu. +0.221211-5 - Prawidłowo obraca obrazek do wydruku +0.221211-4 - W celu okiełzania ramki należy operować wartościami w "self.border_properties" +0.221211-3 - Przycina obrócony obraz, jednak partaczy wydruk +0.221211-2 - Ramka już nie przyrasta vertykalnie +0.221211-0 - Próba implementacji obrotu ramki - do poprawki +0.221210-0 - Przepisanie rozmiaru ramki do słownika. Z sukcesem ! FIXME - zablokować możliwość powiększania ramki po dojściu z jednego z brzegów do konturu. W przeciwnym wypadku kłuci się to z sensownością aplikacji. +0.220317-0 - Dodałem odczyt plików TIFF, jednak aplikacja źle przycina – szare tło +0.220315-1 - Należało by aby aplikacja rozróżniała pochodzenie zdjęcia (lustrzanka, kompakt, smartphone)) w celu doboru współczynnika ramki +0.220314-0 - Drukuje prawidłowo zdjęcia zarówno wertykalne jak i horyzontalne, jednak przy tych ostatnich papier należy również umieścić horyzontalnie w drukarce ! +0.220308-0 - Dalsza korekta ustawień ramki oraz skalowania ramki dla rozmiaru A6 +0.220306-1 - Likwidacja podmenu otwarcia pliku, rozmiar okna dostosowuje się do położenia/rozmiaru zdjęcia. +0.220306-0 - Korekta ramki dla zdjęć horyzontalnych, korekta dotyczy również skalowania tych zdjęć. Jednak są sytuacje gdy dodawana jest ramka do zdjęć. +0.220217-0 - Teraz drukuje ! +0.220216-3 - Korekta przy współżędnych tworzenia ramki, potrzebna korekta ramki przy skalowaniu +0.220216-2 - Małe poprawki w 'Gtk.PaperSize.new.custom' +0.220216-1 - Próba wydruku na orginalnych wymiarach zaraz po przycięciu, nie wiem czy drukarka ruszy... +0.220216-0 - Podbicie nieco pikseli w wydruku, przejście z milimetrów na punkty przy wydruku +0.220214-1 - Przywrócenie poprzednich rozmiarów ramki +0.220214-0 - Rezygnacja ze stalej 0.075 na rzecz nie odejmowania 'crop_y' +0.220213-0 - Przypisanie 'self.pixbuf_tmp' wartości None, oraz zapobiegnięcie wyjścia ramki poza obrazek przy scrolowaniu kółkiem myszki. +0.220212-1 - Kalibracja wydruku +0.220212-0 - Dodałem ograniczenia dla ramki na krawędziach zdjęcia +0.220211-0 - Korekcja wspóczynników ramki dla rozmiaru 13x18 +0.220210-0 - Poprawiłem przywracanie zdjęcia w kontrolce dla 13x18 +0.220205-0 - Wstępne ustawienia dla papieru do wydruku – wszystkie formaty. +0.220204-1 - Przyczółek do korekty wydruku w rozmiarze 10x15 +0.220204-0 - Poprawiłem odświeżenie podglądu po przywróceniu, jednak dla formatu ‘13x18’ odświeżenie bywa problematyczne. Dopisałem opcje drukowania bezpośrednio z ‘prevew’. +0.220202-5 - Dopisałem ustawienia ramki dla pozostałych rozmiarów, uaktualniłem przypisanie rozmiaru obrazka w kontrolce po przywróceniu. +0.220202-4 - Zakomentowanie odjęcia stałej 0,075 od 'bw' - powód: wyjście poza obszar przy przycięciu w okolicach prawego skraju zdjęcia. +0.220202-3 - Optymalizacja kodu → set_ratio_picture_view() +0.220202-2 - Optymalizacja kodu → self.set_ratio_border_size() +0.220202-1 - Włącznie stałej 0,075 również do zmiennej ‘bw’ dla zachowania proporcji obrazu. +0.220202-0 - Ustawienie stałej 0.075 jedynie dla zmiennej ‘bh’, poprawka dla aktualizacji podglądu po przycięciu. +0.220201-2 - Zmniejszenie progresji ramki w funkcji ‘on_mouse_move_in_drawing_area() +0.220201-1 - Dopisanie stalych 0.075 do odjęcia ze źródla wzgldem ramki +0.220201-0 - Poprawiłem przycinanie dolnych partii zdjęcia po przycięciu. Jednak teraz pojawił się narzut po prawej stronie w wyniku. +0.229128-1 - Cyrkulacja ramki +0.220129-0 - Dodałem wyłączenie ramki po przycięciu, przywracanie fotografii do oryginału, po nieudanym przycięciu. Jednak skalowanie ramki nie jest idealne, przy pomniejszonym zaznaczeniu bywa że obcina dół. +0.220128-0 - Napisałem wycinanie brzegów, jednak wycina więcej nie wskazuje ramka ! Potrafi przyciąć nogi. +0.220125-2 - Nieudana propozycja kadrowania +0.220125-1 - Napisałem przycinane zdjęcia, źle kadruje zdjęcia +0.220125-0 - Prawidłowe wyliczenie proporcji ramki dla papieru A6 +0.220124-1 - Próba sformatowania ramki o proporcjach 3/2 dla wszystkich rozmiarów fotografii cyfrowych +0.220124-0 - Poprawiłem odświeżanie ramki po ponownym wczytaniu zdjęcia, skalowana ramka dla wszystkich rozmiarów, jeszcze nie dokładna +0.220123-2 - Dopisałem przesuwanie ramki za pomocą myszki +0.220123-1 - Ustawiłem prawidłowe skalowanie ramki dla rozmiarów 10z15 0raz A4 (13x18 - nie dotyczy) +0.220123-0 - Ramkę można teraz zmniejszać i zwiększać jednak bez ustawionych min. i max. +0.220122-3 - Dodałem plik makefile oraz desktop, oraz ikone png +0.220122-2 - Skrypt prawidłowo wyświetla zdjęcia, zarówno poziomo jak i pionowo. Ramka również jest prawidłowo rysowana - poza zdjęciami w formcie 4:3 ! +0.220122-1 - dodałem kompletną ramkę póki co nieruchomą, dodanie przycisków oraz combobox +0.220122-0 - Zaangażowanie klasy DrawingArea do wyświetlania i rysowania linii, póki co skrypt rysuje pojedynczą linie +0.220121-0 - Rozpoczęcie projektu, wyświetlenie okna z możliwością wczytania i wyświetlenia fotografii diff --git a/configure.gz b/configure.gz Binary files differnew file mode 100644 index 0000000..50437f0 --- /dev/null +++ b/configure.gz diff --git a/data/IMG_6854.JPG b/data/IMG_6854.JPG Binary files differnew file mode 100644 index 0000000..d630aed --- /dev/null +++ b/data/IMG_6854.JPG diff --git a/data/clip.png b/data/clip.png Binary files differnew file mode 100644 index 0000000..43743fd --- /dev/null +++ b/data/clip.png diff --git a/data/photocrop.desktop b/data/photocrop.desktop new file mode 100644 index 0000000..e1ad08e --- /dev/null +++ b/data/photocrop.desktop @@ -0,0 +1,15 @@ +#!/usr/bin/env xdg-open + +[Desktop Entry] +Encoding=UTF-8 +Type=Application +Categories=Graphics; + +Name=Photo Crop + +Exec=python3 /usr/bin/photocrop.py +#Exec=gnome-terminal -e "bash -c 'python3 /usr/bin/photocrop.py;$SHELL'" +Terminal=false +Icon=/usr/share/photocrop/clip.png + +Name[pl_PL]=Przycinanie Zdjęć diff --git a/src/photocrop.py b/src/photocrop.py new file mode 100644 index 0000000..c15e600 --- /dev/null +++ b/src/photocrop.py @@ -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() diff --git a/xcf/clip.xcf b/xcf/clip.xcf Binary files differnew file mode 100644 index 0000000..a63b90e --- /dev/null +++ b/xcf/clip.xcf |