├── .DS_Store ├── .gitignore ├── LICENSE ├── README.md ├── Utils.py ├── __init__.py ├── icon.png ├── image_analyzer.py ├── img └── sample.gif ├── magic_wand.py ├── magic_wand_dockwidget.py ├── magic_wand_dockwidget_base.ui ├── metadata.txt ├── polygon_maker.py ├── resources.py └── resources.qrc /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kanahiro/MagicWand/b6db7d557625aa323f90a106b38d53b179cca6e8/.DS_Store -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__/ -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | {description} 294 | Copyright (C) {year} {fullname} 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | {signature of Ty Coon}, 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MagicWand 2 | QGIS plugin to make polygon easily and automatically by analyzing MapCanvas. 3 | 4 | # Sample 5 | ![QGIS/MagicWand](./img/sample.gif) 6 | 7 | # Usage 8 | - Set Accuracy and Color Threshold, and Click mapcanvas where you want to make polygon. 9 | - Single Mode enable you make ONE polygon around where you clicked. 10 | - Higher Accuracy needs longer time. 11 | - To make polygon apropriately, it is better adjust Saturation highly. 12 | 13 | # Contact 14 | kanahiro.iguchi@gmail.com -------------------------------------------------------------------------------- /Utils.py: -------------------------------------------------------------------------------- 1 | from qgis.core import * 2 | from qgis.gui import * 3 | from qgis.PyQt.QtCore import QPoint 4 | 5 | class ClickTool(QgsMapTool): 6 | def __init__(self, iface, callback): 7 | QgsMapTool.__init__(self,iface.mapCanvas()) 8 | self.iface = iface 9 | self.callback = callback 10 | self.canvas = iface.mapCanvas() 11 | self.drugging = False 12 | return None 13 | 14 | def canvasPressEvent(self,e): 15 | self.drugging = True 16 | point = QPoint(e.pos().x(),e.pos().y()) 17 | self.callback(point) 18 | return None 19 | ''' 20 | def canvasMoveEvent(self,e): 21 | if self.drugging == False: 22 | return None 23 | point = QPoint(e.pos().x(),e.pos().y()) 24 | self.callback(point) 25 | return None 26 | 27 | def canvasReleaseEvent(self,e): 28 | point = QPoint(e.pos().x(),e.pos().y()) 29 | self.callback(point) 30 | self.drugging = False 31 | return None 32 | ''' -------------------------------------------------------------------------------- /__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | /*************************************************************************** 4 | Magicwand 5 | A QGIS plugin 6 | Auto-making Polygon by MapCanvas 7 | Generated by Plugin Builder: http://g-sherman.github.io/Qgis-Plugin-Builder/ 8 | ------------------- 9 | begin : 2019-07-14 10 | copyright : (C) 2019 by Kanahiro Iguchi 11 | email : https://twitter.com/kigchi999 12 | git sha : $Format:%H$ 13 | ***************************************************************************/ 14 | 15 | /*************************************************************************** 16 | * * 17 | * This program is free software; you can redistribute it and/or modify * 18 | * it under the terms of the GNU General Public License as published by * 19 | * the Free Software Foundation; either version 2 of the License, or * 20 | * (at your option) any later version. * 21 | * * 22 | ***************************************************************************/ 23 | This script initializes the plugin, making it known to QGIS. 24 | """ 25 | 26 | 27 | # noinspection PyPep8Naming 28 | def classFactory(iface): # pylint: disable=invalid-name 29 | """Load Magicwand class from file Magicwand. 30 | 31 | :param iface: A QGIS interface instance. 32 | :type iface: QgsInterface 33 | """ 34 | # 35 | from .magic_wand import Magicwand 36 | return Magicwand(iface) 37 | -------------------------------------------------------------------------------- /icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kanahiro/MagicWand/b6db7d557625aa323f90a106b38d53b179cca6e8/icon.png -------------------------------------------------------------------------------- /image_analyzer.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | class ImageAnalyzer: 4 | def __init__(self, image): 5 | self.image = image 6 | 7 | def to_ndarray(self, resize_multiply): 8 | scaled_img = self.resize(self.image, resize_multiply).convertToFormat(4) 9 | 10 | width = scaled_img.width() 11 | height = scaled_img.height() 12 | 13 | ptr = scaled_img.constBits() 14 | ptr.setsize(scaled_img.byteCount()) 15 | arr_rgba = np.array(ptr).reshape(height, width, 4) 16 | arr_rgb = np.delete(arr_rgba, 3, 2) 17 | return arr_rgb 18 | #arr_rgb structure 19 | #img = x1y1 x2y1 ... xny1 20 | # x1y2 x2y2 ... xny2 21 | # ... 22 | # x1yn x2yn ... xnyn 23 | #then ndarray is [[x1y1, x2y1 ... xny1], 24 | # [x1y2, x2y2 ... xny2], 25 | # [x1yn, x2yn ... xnyn]] 26 | #xnyn = [blue, green, red] 27 | 28 | def resize(self, image, resize_multiply): 29 | scaled_img = image.scaled(int(image.width() * resize_multiply), int(image.height() * resize_multiply)) 30 | return scaled_img 31 | 32 | def to_binary(self, point, resize_multiply=0.2, threshold=50): 33 | red, green, blue = self.get_rgb(point) 34 | img_ndarray = self.to_ndarray(resize_multiply) 35 | abs_ndarray = abs(img_ndarray - [blue, green, red]) 36 | sum_ndarray = abs_ndarray.sum(axis=2) 37 | max_ndarray = abs_ndarray.max(axis=2) 38 | true_index = sum_ndarray + max_ndarray*0.5 < threshold 39 | return true_index 40 | 41 | def get_rgb(self, point): 42 | pixelColor = self.image.pixelColor(point.x(), point.y()) 43 | red_value = pixelColor.red() 44 | green_value = pixelColor.green() 45 | blue_value = pixelColor.blue() 46 | return (red_value, green_value, blue_value) -------------------------------------------------------------------------------- /img/sample.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kanahiro/MagicWand/b6db7d557625aa323f90a106b38d53b179cca6e8/img/sample.gif -------------------------------------------------------------------------------- /magic_wand.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | from qgis.PyQt.QtCore import QSettings, QTranslator, QCoreApplication, Qt, QSize 4 | from qgis.PyQt.QtGui import QIcon, QImage, QPainter 5 | from qgis.PyQt.QtWidgets import QAction, QMessageBox 6 | from qgis.core import QgsProject, QgsMapLayer, QgsRectangle, QgsPoint, QgsMultiBandColorRenderer, QgsRaster, QgsMapSettings, QgsMapRendererCustomPainterJob 7 | # Initialize Qt resources from file resources.py 8 | from .resources import * 9 | 10 | # Import the code for the DockWidget 11 | from .magic_wand_dockwidget import MagicwandDockWidget 12 | import os.path 13 | 14 | from .Utils import ClickTool 15 | from .image_analyzer import ImageAnalyzer 16 | from .polygon_maker import PolygonMaker 17 | 18 | 19 | class Magicwand: 20 | """QGIS Plugin Implementation.""" 21 | 22 | def __init__(self, iface): 23 | """Constructor. 24 | 25 | :param iface: An interface instance that will be passed to this class 26 | which provides the hook by which you can manipulate the QGIS 27 | application at run time. 28 | :type iface: QgsInterface 29 | """ 30 | # Save reference to the QGIS interface 31 | self.iface = iface 32 | 33 | self.canvas = iface.mapCanvas() 34 | 35 | # initialize plugin directory 36 | self.plugin_dir = os.path.dirname(__file__) 37 | 38 | # initialize locale 39 | locale = QSettings().value('locale/userLocale')[0:2] 40 | locale_path = os.path.join( 41 | self.plugin_dir, 42 | 'i18n', 43 | 'Magicwand_{}.qm'.format(locale)) 44 | 45 | if os.path.exists(locale_path): 46 | self.translator = QTranslator() 47 | self.translator.load(locale_path) 48 | QCoreApplication.installTranslator(self.translator) 49 | 50 | # Declare instance attributes 51 | self.actions = [] 52 | self.menu = self.tr(u'&Magic Wand') 53 | # TODO: We are going to let the user set this up in a future iteration 54 | self.toolbar = self.iface.addToolBar(u'Magicwand') 55 | self.toolbar.setObjectName(u'Magicwand') 56 | 57 | #print "** INITIALIZING Magicwand" 58 | 59 | self.pluginIsActive = False 60 | self.dockwidget = None 61 | 62 | self.output_layer = None 63 | 64 | 65 | # noinspection PyMethodMayBeStatic 66 | def tr(self, message): 67 | """Get the translation for a string using Qt translation API. 68 | 69 | We implement this ourselves since we do not inherit QObject. 70 | 71 | :param message: String for translation. 72 | :type message: str, QString 73 | 74 | :returns: Translated version of message. 75 | :rtype: QString 76 | """ 77 | # noinspection PyTypeChecker,PyArgumentList,PyCallByClass 78 | return QCoreApplication.translate('Magicwand', message) 79 | 80 | 81 | def add_action( 82 | self, 83 | icon_path, 84 | text, 85 | callback, 86 | enabled_flag=True, 87 | add_to_menu=True, 88 | add_to_toolbar=True, 89 | status_tip=None, 90 | whats_this=None, 91 | parent=None): 92 | """Add a toolbar icon to the toolbar. 93 | 94 | :param icon_path: Path to the icon for this action. Can be a resource 95 | path (e.g. ':/plugins/foo/bar.png') or a normal file system path. 96 | :type icon_path: str 97 | 98 | :param text: Text that should be shown in menu items for this action. 99 | :type text: str 100 | 101 | :param callback: Function to be called when the action is triggered. 102 | :type callback: function 103 | 104 | :param enabled_flag: A flag indicating if the action should be enabled 105 | by default. Defaults to True. 106 | :type enabled_flag: bool 107 | 108 | :param add_to_menu: Flag indicating whether the action should also 109 | be added to the menu. Defaults to True. 110 | :type add_to_menu: bool 111 | 112 | :param add_to_toolbar: Flag indicating whether the action should also 113 | be added to the toolbar. Defaults to True. 114 | :type add_to_toolbar: bool 115 | 116 | :param status_tip: Optional text to show in a popup when mouse pointer 117 | hovers over the action. 118 | :type status_tip: str 119 | 120 | :param parent: Parent widget for the new action. Defaults None. 121 | :type parent: QWidget 122 | 123 | :param whats_this: Optional text to show in the status bar when the 124 | mouse pointer hovers over the action. 125 | 126 | :returns: The action that was created. Note that the action is also 127 | added to self.actions list. 128 | :rtype: QAction 129 | """ 130 | 131 | icon = QIcon(icon_path) 132 | text = "Magic Wand" 133 | action = QAction(icon, text, parent) 134 | action.triggered.connect(callback) 135 | action.setEnabled(enabled_flag) 136 | 137 | if status_tip is not None: 138 | action.setStatusTip(status_tip) 139 | 140 | if whats_this is not None: 141 | action.setWhatsThis(whats_this) 142 | 143 | if add_to_toolbar: 144 | self.toolbar.addAction(action) 145 | 146 | if add_to_menu: 147 | self.iface.addPluginToVectorMenu( 148 | self.menu, 149 | action) 150 | 151 | self.actions.append(action) 152 | 153 | return action 154 | 155 | 156 | def initGui(self): 157 | """Create the menu entries and toolbar icons inside the QGIS GUI.""" 158 | 159 | icon_path = ':/plugins/magic_wand/icon.png' 160 | self.add_action( 161 | icon_path, 162 | text=self.tr(u''), 163 | callback=self.run, 164 | parent=self.iface.mainWindow()) 165 | 166 | #-------------------------------------------------------------------------- 167 | 168 | def onClosePlugin(self): 169 | """Cleanup necessary items here when plugin dockwidget is closed""" 170 | 171 | #print "** CLOSING Magicwand" 172 | 173 | # disconnects 174 | self.dockwidget.closingPlugin.disconnect(self.onClosePlugin) 175 | 176 | # remove this statement if dockwidget is to remain 177 | # for reuse if plugin is reopened 178 | # Commented next statement since it causes QGIS crashe 179 | # when closing the docked window: 180 | # self.dockwidget = None 181 | 182 | self.pluginIsActive = False 183 | 184 | 185 | def unload(self): 186 | """Removes the plugin menu item and icon from QGIS GUI.""" 187 | 188 | #print "** UNLOAD Magicwand" 189 | 190 | for action in self.actions: 191 | self.iface.removePluginVectorMenu( 192 | self.tr(u'&Magic Wand'), 193 | action) 194 | self.iface.removeToolBarIcon(action) 195 | # remove the toolbar 196 | del self.toolbar 197 | 198 | #-------------------------------------------------------------------------- 199 | 200 | #actions on mapcanvas clicked 201 | def click_action(self, point): 202 | mapSettings = self.iface.mapCanvas().mapSettings() 203 | image = self.make_image(mapSettings) 204 | image_analyzer = ImageAnalyzer(image) 205 | #get slider value 206 | resize_multiply = self.dockwidget.accuracy_slider.value() / 100 207 | threshold = 100 - self.dockwidget.threshold_slider.value() 208 | bin_index = image_analyzer.to_binary(point, resize_multiply, threshold) 209 | 210 | polygon_maker = PolygonMaker(self.iface.mapCanvas(), bin_index) 211 | project_crs = QgsProject.instance().crs() 212 | single_mode = self.dockwidget.single_mode.isChecked() 213 | selected_layer_id = self.dockwidget.layerComboBox.currentData() 214 | 215 | polygon_maker.make_polygons(point, crs=project_crs, single_mode=single_mode, layer_id=selected_layer_id) 216 | 217 | selected_index = self.dockwidget.layerComboBox.currentIndex() 218 | self.reload_combo_box() 219 | self.dockwidget.layerComboBox.setCurrentIndex(selected_index) 220 | self.canvas.refreshAllLayers() 221 | 222 | return 223 | 224 | #make and return QImage from MapCanvas 225 | def make_image(self, mapSettings): 226 | image = QImage(mapSettings.outputSize(), QImage.Format_RGB32) 227 | p = QPainter() 228 | p.begin(image) 229 | mapRenderer = QgsMapRendererCustomPainterJob(mapSettings, p) 230 | mapRenderer.start() 231 | mapRenderer.waitForFinished() 232 | p.end() 233 | return image 234 | 235 | def enable_magicwand(self): 236 | ct = ClickTool(self.iface, self.click_action) 237 | self.previous_map_tool = self.iface.mapCanvas().mapTool() 238 | self.iface.mapCanvas().setMapTool(ct) 239 | 240 | def init_sliders(self): 241 | self.dockwidget.accuracy_slider.setMinimum(20) 242 | self.dockwidget.accuracy_slider.setMaximum(100) 243 | self.dockwidget.accuracy_slider.setSingleStep(20) 244 | self.dockwidget.accuracy_slider.setValue(60) 245 | 246 | self.dockwidget.threshold_slider.setMinimum(10) 247 | self.dockwidget.threshold_slider.setMaximum(90) 248 | self.dockwidget.threshold_slider.setSingleStep(10) 249 | self.dockwidget.threshold_slider.setValue(50) 250 | 251 | def reload_combo_box(self): 252 | self.dockwidget.layerComboBox.clear() 253 | self.dockwidget.layerComboBox.addItem('===New Layer===',0) 254 | layers = QgsProject.instance().mapLayers() 255 | for key, layer in layers.items(): 256 | if layer.type() == QgsMapLayer.VectorLayer: 257 | #key is ID of each layers 258 | self.dockwidget.layerComboBox.addItem(layer.name(),key) 259 | 260 | def run(self): 261 | """Run method that loads and starts the plugin""" 262 | 263 | if not self.pluginIsActive: 264 | self.pluginIsActive = True 265 | 266 | #print "** STARTING Magicwand" 267 | 268 | # dockwidget may not exist if: 269 | # first run of plugin 270 | # removed on close (see self.onClosePlugin method) 271 | if self.dockwidget == None: 272 | # Create the dockwidget (after translation) and keep reference 273 | self.dockwidget = MagicwandDockWidget() 274 | 275 | # connect to provide cleanup on closing of dockwidget 276 | self.dockwidget.closingPlugin.connect(self.onClosePlugin) 277 | 278 | # show the dockwidget 279 | self.iface.addDockWidget(Qt.TopDockWidgetArea, self.dockwidget) 280 | self.dockwidget.show() 281 | 282 | ct = ClickTool(self.iface, self.click_action) 283 | self.previous_map_tool = self.iface.mapCanvas().mapTool() 284 | self.iface.mapCanvas().setMapTool(ct) 285 | 286 | self.dockwidget.enable_button.clicked.connect(self.enable_magicwand) 287 | 288 | QgsProject.instance().layersAdded.connect(self.reload_combo_box) 289 | QgsProject.instance().layersRemoved.connect(self.reload_combo_box) 290 | self.reload_combo_box() 291 | self.init_sliders() -------------------------------------------------------------------------------- /magic_wand_dockwidget.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import os 4 | 5 | from qgis.PyQt import QtGui, QtWidgets, uic 6 | from qgis.PyQt.QtCore import pyqtSignal 7 | 8 | FORM_CLASS, _ = uic.loadUiType(os.path.join( 9 | os.path.dirname(__file__), 'magic_wand_dockwidget_base.ui')) 10 | 11 | 12 | class MagicwandDockWidget(QtWidgets.QDockWidget, FORM_CLASS): 13 | 14 | closingPlugin = pyqtSignal() 15 | 16 | def __init__(self, parent=None): 17 | """Constructor.""" 18 | super(MagicwandDockWidget, self).__init__(parent) 19 | # Set up the user interface from Designer. 20 | # After setupUI you can access any designer object by doing 21 | # self., and you can use autoconnect slots - see 22 | # http://doc.qt.io/qt-5/designer-using-a-ui-file.html 23 | # #widgets-and-dialogs-with-auto-connect 24 | self.setupUi(self) 25 | 26 | def closeEvent(self, event): 27 | self.closingPlugin.emit() 28 | event.accept() 29 | -------------------------------------------------------------------------------- /magic_wand_dockwidget_base.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | MagicwandDockWidgetBase 4 | 5 | 6 | 7 | 0 8 | 0 9 | 342 10 | 119 11 | 12 | 13 | 14 | Magic Wand 15 | 16 | 17 | 18 | 19 | 20 | 21 | Enable 22 | 23 | 24 | 25 | 26 | 27 | 28 | Fast 29 | 30 | 31 | 32 | 33 | 34 | 35 | Accuracy 36 | 37 | 38 | 39 | 40 | 41 | 42 | Color Threshold 43 | 44 | 45 | 46 | 47 | 48 | 49 | Ambiguous 50 | 51 | 52 | 53 | 54 | 55 | 56 | Qt::Horizontal 57 | 58 | 59 | 60 | 61 | 62 | 63 | Qt::Horizontal 64 | 65 | 66 | 67 | 68 | 69 | 70 | Precise 71 | 72 | 73 | 74 | 75 | 76 | 77 | Single Mode 78 | 79 | 80 | 81 | 82 | 83 | 84 | Strict 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /metadata.txt: -------------------------------------------------------------------------------- 1 | # This file contains metadata for your plugin. 2 | 3 | # This file should be included when you package your plugin.# Mandatory items: 4 | 5 | [general] 6 | name=Magic Wand 7 | qgisMinimumVersion=3.0 8 | description=Auto-making Polygon by MapCanvas 9 | version=1.3.2 10 | author=Kanahiro Iguchi 11 | email=kanahiro.iguchi@gmail.com 12 | 13 | about=QGIS plugin to make polygon easily and automatically by analysing MapCanvas. 14 | 15 | tracker=https://github.com/Kanahiro/MagicWand/issues 16 | repository=https://github.com/Kanahiro/MagicWand 17 | # End of mandatory metadata 18 | 19 | # Recommended items: 20 | 21 | hasProcessingProvider=no 22 | # Uncomment the following line and add your changelog: 23 | # changelog= 24 | 25 | # Tags are comma separated with spaces allowed 26 | tags=python 27 | 28 | homepage=https://kiguchi999.hatenablog.com/ 29 | category=Vector 30 | icon=icon.png 31 | # experimental flag 32 | experimental=False 33 | 34 | # deprecated flag (applies to the whole plugin, not just a single version) 35 | deprecated=False 36 | 37 | # Since QGIS 3.8, a comma separated list of plugins to be installed 38 | # (or upgraded) can be specified. 39 | # Check the documentation for more information. 40 | # plugin_dependencies= 41 | 42 | Category of the plugin: Raster, Vector, Database or Web 43 | # category= 44 | 45 | # If the plugin can run on QGIS Server. 46 | server=False 47 | 48 | -------------------------------------------------------------------------------- /polygon_maker.py: -------------------------------------------------------------------------------- 1 | from qgis.core import QgsProject, QgsRectangle, QgsVectorLayer, QgsFeature, QgsGeometry, QgsCoordinateTransform 2 | import processing 3 | import numpy as np 4 | 5 | class PolygonMaker: 6 | def __init__(self, canvas, bin_index): 7 | self.bin_index = bin_index 8 | self.map_canvas = canvas 9 | self.size_multiply = self.map_canvas.width() / self.bin_index.shape[1] 10 | self.minimum_area = self.make_rect(0,0, self.size_multiply).area() 11 | self.noise_multiply = 40 12 | 13 | def make_polygons(self, point, crs, single_mode=False, layer_id=None): 14 | rects = self.make_rects() 15 | rects_layer = self.make_layer_by(rects, crs) 16 | 17 | dissolved_layer = processing.run('qgis:dissolve', {'INPUT':rects_layer,'OUTPUT':'memory:'})['OUTPUT'] 18 | single_part_layer = processing.run('qgis:multiparttosingleparts', {'INPUT':dissolved_layer,'OUTPUT':'memory:'})['OUTPUT'] 19 | single_features = single_part_layer.getFeatures() 20 | 21 | if single_mode: 22 | for feature in single_features: 23 | if feature.geometry().contains(self.map_canvas.getCoordinateTransform().toMapPoint(point.x(), point.y())): 24 | single_features = [feature] 25 | break 26 | 27 | denoised_features = self.noise_reduction(single_features, self.noise_multiply) 28 | denoised_layer = self.make_layer_by(denoised_features, crs) 29 | cleaned_layer = processing.run('qgis:deleteholes', {'INPUT':denoised_layer, 'MIN_AREA':self.minimum_area * self.size_multiply * self.noise_multiply, 'OUTPUT':'memory:'})['OUTPUT'] 30 | cleaned_features = cleaned_layer.getFeatures() 31 | 32 | #output layer 33 | output = QgsVectorLayer('Polygon?crs=' + crs.authid() + '&field=MYNYM:integer&field=MYTXT:string', 'magic_wand', 'memory') 34 | if layer_id: 35 | output = QgsProject.instance().mapLayer(layer_id) 36 | 37 | output_provider = output.dataProvider() 38 | output_provider.addFeatures(cleaned_features) 39 | 40 | QgsProject.instance().addMapLayer(output) 41 | 42 | #make rectangle geometry by pointXY on Pixels 43 | def make_rect(self, x, y, size_multiply, count=0): 44 | pointTopLeft = self.map_canvas.getCoordinateTransform().toMapPoint(x * size_multiply, y * size_multiply) 45 | pointBottomRight = self.map_canvas.getCoordinateTransform().toMapPoint((x + count + 1) * size_multiply, (y + 1) * size_multiply) 46 | 47 | geo = QgsGeometry.fromRect(QgsRectangle(pointTopLeft.x(), pointTopLeft.y(), pointBottomRight.x(), pointBottomRight.y())) 48 | return geo 49 | 50 | def make_rects(self): 51 | #make 2d array including only TRUE pixel index 52 | #true_points[0]:y axis indexes 53 | #true_points[1]:x axis indexes 54 | true_points = np.where(self.bin_index) 55 | 56 | #rectangle making sequence 57 | geos = [] 58 | #when neighbor pixel also true, incliment this count 59 | connectedCount = 0 60 | for i in range(len(true_points[0])): 61 | #skip loops same number to the count 62 | if connectedCount > 0: 63 | connectedCount = connectedCount - 1 64 | continue 65 | 66 | x = true_points[1][i] 67 | y = true_points[0][i] 68 | 69 | #when the final loop 70 | if i >= len(true_points[0]) - 1: 71 | geos.append(self.make_rect(x, y, self.size_multiply)) 72 | break 73 | 74 | #calculate connectedCount 75 | while true_points[1][i + connectedCount + 1] - true_points[1][i + connectedCount] == 1: 76 | connectedCount = connectedCount + 1 77 | if i + connectedCount + 1 >= len(true_points[0]) - 1: 78 | break 79 | 80 | geos.append(self.make_rect(x, y, self.size_multiply, connectedCount)) 81 | 82 | rects = [] 83 | for geo in geos: 84 | rect = QgsFeature() 85 | rect.setGeometry(geo) 86 | rects.append(rect) 87 | return rects 88 | 89 | def make_layer_by(self, features, crs): 90 | features_layer = QgsVectorLayer('Polygon?crs=' + crs.authid() + '&field=MYNYM:integer&field=MYTXT:string', 'magic_wand', 'memory') 91 | features_layer_provider = features_layer.dataProvider() 92 | features_layer_provider.addFeatures(features) 93 | return features_layer 94 | 95 | def noise_reduction(self, features, noise_multiply, torel_multiply=2.5): 96 | output = [] 97 | torelance = self.map_canvas.mapUnitsPerPixel() * torel_multiply * self.size_multiply ** 0.6 98 | for feature in features: 99 | if feature.geometry().area() < self.minimum_area * noise_multiply: 100 | continue 101 | output_geo = feature.geometry().simplify(torelance) 102 | output_feature = QgsFeature() 103 | output_feature.setGeometry(output_geo) 104 | output.append(output_feature) 105 | 106 | return output -------------------------------------------------------------------------------- /resources.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Resource object code 4 | # 5 | # Created by: The Resource Compiler for PyQt5 (Qt v5.9.6) 6 | # 7 | # WARNING! All changes made in this file will be lost! 8 | 9 | from PyQt5 import QtCore 10 | 11 | qt_resource_data = b"\ 12 | \x00\x00\x0c\x14\ 13 | \x89\ 14 | \x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\ 15 | \x00\x00\x80\x00\x00\x00\x80\x08\x06\x00\x00\x00\xc3\x3e\x61\xcb\ 16 | \x00\x00\x0b\xdb\x49\x44\x41\x54\x78\x5e\xed\x9d\x7f\xac\x5c\x45\ 17 | \x15\xc7\xcf\xb9\xfb\x2a\xbc\xdd\x06\x2a\x69\xc5\x54\x21\x44\xf9\ 18 | \x91\x48\x4c\x2d\x82\x11\x8a\xb2\x60\xdb\xd7\x3b\xb3\x6b\x5a\xda\ 19 | \xa7\x62\x82\x02\xa2\xd4\x04\x14\xa8\x28\x3f\xfe\x40\xff\x90\x20\ 20 | \xa8\x68\xa2\x52\x0c\x88\x28\x6a\xe3\x93\x40\xfa\x76\x66\xf7\xbd\ 21 | \xf6\xc9\xca\x0f\x21\x28\x15\xd1\x98\x58\xc1\x20\xfe\xd1\xb4\xd8\ 22 | \x8a\xa9\xef\x99\x47\xf7\xdd\x63\xa6\xdc\x85\xed\x76\xdf\xdb\x7b\ 23 | \xe7\xde\x9d\xbd\x77\xef\xdc\x7f\xda\xe4\xcd\x39\x67\xe6\x7c\x3f\ 24 | \x77\xee\xdc\xb9\xb3\x33\x08\xf6\xca\x74\x06\x30\xd3\xad\xb7\x8d\ 25 | \x07\x0b\x40\xc6\x21\xb0\x00\x58\x00\x32\x9e\x81\x8c\x37\xdf\xf6\ 26 | \x00\x16\x80\x8c\x67\x20\xe3\xcd\xb7\x3d\x40\x0c\x00\x94\xcb\xe5\ 27 | \xa5\x07\x0f\x1e\x6c\xd4\xeb\xf5\x57\x63\x70\x67\xd4\x85\x05\x20\ 28 | \x62\xba\x8b\xc5\xe2\x50\x3e\x9f\x7f\x19\x11\xbd\xe9\xe9\xe9\x53\ 29 | \xea\xf5\x7a\x23\xa2\x4b\xa3\xe6\x16\x80\x88\xe9\x2e\x95\x4a\x45\ 30 | \x22\x7a\x54\xb9\xf1\x3c\xef\xfc\x6a\xb5\xfa\x64\x44\x97\x46\xcd\ 31 | \x2d\x00\x11\xd3\xcd\x39\xff\x3a\x00\xdc\xac\xdc\x10\xd1\x57\xa5\ 32 | \x94\x5f\x8b\xe8\xd2\xa8\xb9\x05\x20\x62\xba\x19\x63\xcf\x20\xe2\ 33 | \x39\x3e\x00\x4f\x4a\x29\xcf\x8f\xe8\xd2\xa8\xb9\x05\x20\x42\xba\ 34 | \x8b\xc5\xe2\x92\x7c\x3e\x7f\x00\x11\x0f\xe7\x91\x88\x1a\x8d\x46\ 35 | \x63\xc9\xe4\xe4\xe4\x74\x04\xb7\x46\x4d\x2d\x00\x11\xd2\xed\xba\ 36 | \xee\x26\xc7\x71\xc6\x5a\x5d\x78\x9e\xf7\xd1\x6a\xb5\x3a\x1e\xc1\ 37 | \xad\x51\x53\x0b\x40\x84\x74\x73\xce\x7f\x08\x00\x9f\x6d\x75\x41\ 38 | \x44\xdf\x97\x52\x5e\x1d\xc1\xad\x51\x53\x0b\x80\x66\xba\x5d\xd7\ 39 | \x3d\x06\x11\xf7\x21\xe2\x71\x6d\x2e\xf6\x7b\x9e\xf7\x8e\x6a\xb5\ 40 | \x3a\xab\xe9\xda\xa8\x99\x05\x40\x33\xdd\x8c\xb1\x9b\x10\xf1\xb6\ 41 | \x79\xcc\x6f\x14\x42\x7c\x43\xd3\xb5\x51\x33\x0b\x80\x46\xba\x5d\ 42 | \xd7\x2d\x3b\x8e\xf3\x08\x00\x38\x9d\xcc\xd5\x60\x10\x11\xd7\x0b\ 43 | \x21\x84\x86\x7b\xa3\x26\x16\x80\x10\xe9\x76\x5d\xf7\xdd\x8e\xe3\ 44 | \x6c\x26\xa2\x2d\xcd\x91\xff\x02\xe6\x1e\x11\xdd\x41\x44\xf7\x56\ 45 | \xab\xd5\x17\x43\x84\x31\x5a\xd4\x02\xb0\x40\xba\x8b\xc5\xe2\xe2\ 46 | \xe1\xe1\xe1\x0b\x1d\xc7\x59\x4b\x44\x6b\x11\xf1\x74\x1d\x75\x88\ 47 | \x68\x37\x22\x4e\x10\xd1\x64\x2e\x97\xfb\xf5\xf8\xf8\xf8\x8c\x8e\ 48 | \x9f\x5e\xd8\x58\x00\xda\xb2\x3a\x32\x32\x72\xe6\xd0\xd0\xd0\x7a\ 49 | \x25\x38\x00\x9c\x87\x88\x43\x71\x26\x9e\x88\x0e\x01\xc0\x6f\x01\ 50 | \x60\xc2\xf3\xbc\x5f\xd4\x6a\xb5\x97\xe2\xf4\x1f\xd6\x97\x05\xa0\ 51 | \x25\x63\xa3\xa3\xa3\x6f\x99\x99\x99\x51\x77\x67\x2e\x6c\x22\x75\ 52 | \xca\x13\xd1\x2b\x33\x33\x33\xcb\xfb\xf9\x01\xc9\x02\xd0\xa6\x1c\ 53 | \xe7\xfc\x2e\x00\xf8\x1c\x00\xe4\x75\x44\x0d\x61\x33\x43\x44\x0f\ 54 | \x49\x29\x3f\x15\xc2\x26\xf6\xa2\x16\x80\x0e\x29\xf5\x7b\x82\x55\ 55 | \xfe\x73\x5f\x3d\xff\x57\x06\x18\xf4\x2d\x28\x0e\x11\x11\x22\xee\ 56 | \x52\xe3\x00\xc7\x71\x26\xf7\xec\xd9\xf3\xe4\xb3\xcf\x3e\xab\x1e\ 57 | \x07\x7d\xbd\x2c\x00\x01\xd2\xef\xba\xee\x32\x44\x5c\x83\x88\x2e\ 58 | \x00\x6c\x04\x80\xe1\x00\x66\xaa\xc8\xff\x00\xe0\x21\x00\x10\x8d\ 59 | \x46\x63\x72\x62\x62\xe2\x40\x40\x3b\x63\xc5\x22\x01\xc0\x39\xbf\ 60 | \x99\x88\x4e\x22\xa2\x6b\xd3\x32\xf3\x15\x35\xb3\x3e\x0c\xdb\x11\ 61 | \xf1\x83\x0b\xf9\x22\xa2\xa7\x67\x67\x67\x4b\x53\x53\x53\xfb\xa3\ 62 | \xc6\xec\xa5\xbd\x36\x00\xfe\x3b\xf1\x0b\x7e\xe5\x2e\x11\x42\x6c\ 63 | \xeb\x65\x45\x93\xe4\xbb\x58\x2c\x1e\x5b\x28\x14\x9e\x06\x80\x15\ 64 | \x9d\xea\x45\x44\xcf\xef\xdd\xbb\xf7\xec\x24\x74\xf1\xdd\xf2\xa6\ 65 | \x0d\x00\x63\xec\x2a\x44\xdc\xaa\x02\x10\xd1\x7d\x52\xca\x2b\xbb\ 66 | \x05\x1b\xa4\xbf\xfb\xaf\x8b\x7f\xee\xd4\x26\xcf\xf3\xce\xac\x56\ 67 | \xab\x7f\x49\x43\x7b\xb5\x01\xe0\x9c\xab\xcf\xa0\x9b\x7c\x00\xfe\ 68 | \x29\xa5\x3c\x39\x0d\x0d\x8e\xb3\x8e\x8c\xb1\x27\x10\x71\x55\xab\ 69 | \x4f\x22\x7a\x4c\x4a\x79\x41\x9c\x71\x7a\xe9\x4b\x17\x00\xe4\x9c\ 70 | \xab\x01\xcd\x92\x66\xe5\x1a\x8d\xc6\x69\x13\x13\x13\xcd\x47\x42\ 71 | \x2f\xeb\x9c\x18\xdf\x8c\xb1\x1b\x10\xf1\x8e\x36\x00\xae\x97\x52\ 72 | \xaa\x57\xc9\x54\x5c\x5a\x00\x70\xce\xdf\x0f\x00\xbf\x6f\x6b\xf8\ 73 | \xe7\xa5\x94\x87\x1f\x09\x59\xb9\x5c\xd7\x5d\xe9\x38\xce\xae\xb6\ 74 | \xf6\xbe\x57\x08\xd1\xf1\xd1\x90\xc4\xbc\xe8\x02\xf0\x15\x00\xb8\ 75 | \xbd\x0d\x00\x35\xa9\x71\xf8\x91\x90\xa5\x8b\x73\xfe\xef\x66\x4f\ 76 | \x48\x44\xfb\xa4\x94\x27\xa6\xa9\xfd\xba\x00\xec\x00\x80\xd5\x6d\ 77 | \x0d\x7d\x55\x08\x71\x82\x1a\x13\xf6\x3b\x01\x6a\xa9\x76\xa5\x52\ 78 | \xa9\x9b\xa8\x07\x63\x6c\x1b\x22\x7e\xdc\x1f\x0b\xfd\x44\x4a\xf9\ 79 | \x69\x13\x71\xe3\x8a\x11\x1a\x00\xd7\x75\x8f\xf3\x57\xc2\x1c\xd3\ 80 | \x5e\x09\x22\xba\x40\x4a\xf9\x58\x5c\x95\xd3\xf1\xc3\x18\xbb\x0c\ 81 | \x11\xef\x27\xa2\x1f\x4b\x29\x2f\xd7\xf1\x11\xc6\x86\x73\xfe\x19\ 82 | \x00\xb8\xd7\xb7\xb9\x54\x08\xf1\x60\x18\xfb\x7e\x97\x0d\x0d\x00\ 83 | \x63\xec\x0b\x88\xf8\xdd\x79\x2a\xfe\xa0\x10\xe2\xd2\x7e\x35\xaa\ 84 | \x29\x7e\x33\xbe\x09\x08\xd6\xae\x5d\x7b\xd2\xa2\x45\x8b\x5e\x56\ 85 | \x31\x0f\x1d\x3a\x74\xe2\xe4\xe4\xe4\xbe\x7e\xb5\x5f\x27\x6e\x28\ 86 | \x00\xfc\xc9\x1f\x35\xf8\x7b\x63\xf4\xdf\x36\x0e\x68\x38\x8e\xb3\ 87 | \xaa\x52\xa9\x3c\xa3\x53\x99\x28\x36\xed\xe2\x9b\x84\x80\x73\x7e\ 88 | \x0b\x00\x34\xd2\xb2\x0c\xac\x35\xcf\x81\x01\xe0\x9c\xbf\x0b\x00\ 89 | \xd4\x4f\xa0\xba\xbd\xef\xab\xbb\xe1\x42\x21\xc4\xdf\xa3\x08\x1a\ 90 | \xc6\x76\x3e\xf1\x4d\x42\x10\xa6\xbe\x49\x2a\xdb\x15\x00\xff\xc7\ 91 | \x8f\x1f\x43\xc4\xef\x01\xc0\x5b\x03\x56\x5e\x7d\x53\xbf\x75\x7a\ 92 | \x7a\x7a\x6b\xbd\x5e\xff\x6f\x40\x1b\xad\x62\xdd\xc4\xb7\x10\x2c\ 93 | \x9c\xd6\x8e\x00\xa8\xa5\x50\xf9\x7c\xbe\x88\x88\xea\x53\xe8\x06\ 94 | \x44\x7c\xa7\x96\x3a\x00\x07\x89\xe8\x61\xb5\xfa\x65\x76\x76\x76\ 95 | \x22\xee\x0f\x23\x41\xc5\xb7\x10\xcc\xaf\x5e\x13\x00\x35\xb3\x77\ 96 | \x56\xcb\xf7\xef\x55\x88\xb8\x48\x53\xf4\x8e\x66\xea\x7b\x38\x00\ 97 | \x3c\x87\x88\x93\x9e\xe7\x4d\x2e\x5e\xbc\xf8\x89\xb1\xb1\xb1\xd7\ 98 | \x74\x63\x84\x15\xdf\x42\xd0\x39\xd3\xc8\x18\xfb\x22\x22\xde\x1a\ 99 | \xa2\x7b\xd7\xd5\xac\xdd\x4e\x7d\x2b\xaf\xe5\xf3\xf9\x4f\x84\x05\ 100 | \x41\x57\x7c\x0b\xc1\xd1\xd2\x29\x00\xf6\x20\xe2\xdb\xe3\x52\x35\ 101 | \xac\x9f\x46\xa3\xb1\x7c\x62\x62\x62\x4f\x50\xbb\xa8\xe2\x5b\x08\ 102 | \x8e\xcc\xb4\xea\xfa\xcf\x03\x80\x6b\x88\x48\x3d\xf3\x4d\x81\xa0\ 103 | \xb6\x52\x51\x1b\x29\xa8\x79\x83\xc0\xeb\x08\xe2\x12\xdf\x42\xf0\ 104 | \x26\x04\x47\x0c\x02\xfd\x57\xbd\x0f\x01\xc0\x87\x01\x40\xfd\x7b\ 105 | \x5a\xd0\x3b\x73\xa1\x72\x44\xa4\xee\xf0\xc7\x89\xe8\xf1\x5c\x2e\ 106 | \xf7\x78\xa5\x52\x79\x3e\xec\x94\x71\xdc\xe2\x5b\x08\x5e\xcf\xc0\ 107 | \x82\xaf\x81\xfe\xf2\xa7\x8b\x01\xe0\x3a\x44\x3c\x23\x0c\x0c\xea\ 108 | \xc3\x08\x00\xfc\xc0\xf3\xbc\x6d\xb5\x5a\xed\xaf\x61\x6c\xdb\xcb\ 109 | \xf6\x4a\x7c\x0b\x41\x17\x00\x5a\x84\x50\x8f\x8a\x2d\x44\x74\x5b\ 110 | \x90\xb7\x03\xb5\x28\x62\x68\x68\xa8\xb4\x7d\xfb\xf6\x83\x51\x84\ 111 | \x57\xb6\xbd\x16\x3f\xeb\x10\x74\x9d\x08\x6a\x15\x90\x31\xf6\x49\ 112 | \x44\xfc\x59\x97\xee\xbe\xb2\x77\xef\xde\x8b\xe3\x5a\x0f\x67\x0a\ 113 | \x00\x00\x78\x40\x08\x71\x59\x54\x60\xd3\x66\x1f\x0a\x00\xd5\x38\ 114 | \xce\xf9\x2f\x01\x60\x74\x9e\x86\xfe\xed\xc0\x81\x03\x2b\x9e\x7a\ 115 | \xea\x29\xf5\x8a\x17\xdb\x65\x00\x82\x4c\x8a\xdf\x75\x0c\xd0\x49\ 116 | \x41\xd7\x75\x57\x39\x8e\xf3\xc4\x3c\xea\x5e\x27\x84\xf8\x4e\x6c\ 117 | \xca\xb7\x38\xea\x21\x04\x99\x15\x5f\x0b\x00\xbf\x17\x50\x3f\x77\ 118 | \x56\x1f\x87\x8e\xb8\x1c\xc7\x59\x36\x3e\x3e\xfe\xaf\x5e\x00\xd0\ 119 | \xa3\xf1\x40\xa6\xc5\xd7\x06\x80\x31\xb6\x15\x11\xaf\x6a\x15\x9a\ 120 | \x88\xfe\x20\xa5\x3c\xab\x57\xe2\x37\xfd\xc6\xd8\x13\x64\x5e\x7c\ 121 | \x6d\x00\x38\xe7\x6a\x0c\xa0\xc6\x02\x6f\x5c\x44\x74\xa7\x94\xf2\ 122 | \xcb\xbd\x06\x20\xa6\x9e\xc0\x8a\xef\x0b\x15\x7a\x10\xe8\x3f\x02\ 123 | \xd4\x67\xe1\x23\x7e\xe7\xe6\x79\xde\x48\xb5\x5a\x9d\x34\x01\x40\ 124 | \x44\x08\x42\x8b\xbf\x7a\xf5\xea\xe3\x77\xee\xdc\xf9\x1f\x53\x6d\ 125 | \x33\x19\x47\x0b\x00\x5f\x80\x5d\x88\xb8\x52\xfd\x5f\xed\x89\x43\ 126 | \x44\x8b\x4d\xff\x3e\x50\xe3\x71\x10\x5a\x7c\x7f\x33\x48\xb5\x10\ 127 | \xe6\xf9\xb4\x2d\xf8\x0c\x02\x92\x36\x00\x9c\xf3\x3b\x01\xe0\x4b\ 128 | \x3e\x00\x8f\x4a\x29\x2f\x0a\x12\x30\xee\x32\x21\x20\xd0\x16\x1f\ 129 | \x11\xdf\xe7\xb7\x33\x75\xab\x7e\xbb\xe5\x5b\x1b\x00\xc6\xd8\x3a\ 130 | \x44\xac\xfa\x01\x6e\x11\x42\xcc\xb7\x65\x5a\xb7\x3a\x44\xfe\x7b\ 131 | \x00\x08\x22\x8b\xdf\xac\x24\x11\x0d\x14\x04\xda\x00\x94\xcb\xe5\ 132 | \xfc\xdc\xdc\xdc\x4b\x88\xb8\x0c\x00\xfa\xfe\x6b\x98\x05\x20\x88\ 133 | \x4d\xfc\x41\x84\x40\x1b\x00\x95\x8c\x75\xeb\xd6\x9d\x92\xcb\xe5\ 134 | \xce\x11\x42\x1c\xb1\x5f\x6e\xe4\x5b\x5a\xd3\x41\x07\x08\x62\x17\ 135 | \xbf\x15\x82\x42\xa1\x70\xc5\xd8\xd8\xd8\x9c\x66\x75\x13\x61\x16\ 136 | \x09\x80\x44\xb4\xa0\xad\x12\x2d\x10\xf4\x4c\xfc\x96\x90\x0f\xe7\ 137 | \xf3\xf9\xd1\x34\x43\x30\x70\x00\x28\x71\x74\x7e\x1a\xd6\x1c\xed\ 138 | \x37\x07\x7c\x21\xe0\x4e\x35\x04\x03\x09\x40\x08\xf1\x0e\x17\x8d\ 139 | \x20\x7e\x33\x54\x6a\x21\xc8\x3c\x00\x31\x88\x9f\x6a\x08\x32\x0d\ 140 | \x40\x8c\xe2\xa7\x16\x82\xcc\x02\xd0\x03\xf1\x53\x09\x41\x26\x01\ 141 | \xe8\xa1\xf8\xa9\x83\x20\x73\x00\x18\x10\x3f\x55\x10\x64\x0e\x00\ 142 | \xd7\x75\xd7\x3b\x8e\xa3\x7e\xaf\xd8\xf3\xcb\xdf\x0b\x38\xd1\xdb\ 143 | \xe6\x64\x0e\x00\xa5\x3a\x63\x4c\x6d\x62\xf1\x40\xd4\xfd\x7f\x03\ 144 | \x12\x94\xe8\x57\xc4\x4c\x02\x60\x21\x78\x13\xdd\xcc\x02\x60\x21\ 145 | \x78\x1d\x82\x4c\x03\x60\x21\xb0\x00\x1c\xbe\x0b\xb2\x3c\x26\xc8\ 146 | \x7c\x0f\xd0\x7c\x1a\x66\x15\x02\x0b\x40\xcb\x50\x3e\x8b\x10\x58\ 147 | \x00\x8e\x5e\x4f\x90\xa9\x57\x44\x0b\x40\x87\x97\xf9\x2c\xf5\x04\ 148 | \x16\x80\x79\x66\x73\xb2\x02\x81\x05\x60\x81\xe9\xbc\x2c\x40\x60\ 149 | \x01\xe8\x32\x9f\x3b\xe8\x10\x58\x00\x02\x4c\xe8\x0f\x32\x04\xa9\ 150 | \x05\x80\x31\x76\x23\x00\x9c\x61\x62\x4b\xf8\x41\x9e\x2c\x4a\x2d\ 151 | \x00\x9c\xf3\xdd\x44\x74\x32\x11\x1d\x6f\xea\x37\x89\x83\xd8\x13\ 152 | \xa4\x12\x80\x72\xb9\x7c\xb2\xe7\x79\xff\x50\x77\xe6\xdc\xdc\xdc\ 153 | \xea\x5a\xad\x36\x15\xa0\x27\x8f\xa5\xc8\xa0\x41\x90\x4a\x00\x38\ 154 | \xe7\x57\x00\xc0\x7d\x4a\x51\x22\xba\x5d\x4a\x79\x53\x2c\xea\x06\ 155 | \x74\x32\x48\x10\xa4\x12\x00\xc6\xd8\xcf\x11\xf1\x12\x1f\x80\xdf\ 156 | \x49\x29\x3f\x10\x50\xbb\xd8\x8a\x0d\x0a\x04\xa9\x03\x40\x9d\x5f\ 157 | \x50\x28\x14\xd4\xce\xa3\x4b\x7d\x00\x28\x97\xcb\xbd\xad\x97\x7b\ 158 | \x13\xcd\x47\xcd\x20\x40\x90\x3a\x00\x18\x63\x9b\x11\xf1\xee\x36\ 159 | \x51\x6e\x10\x42\x7c\x33\xb6\xdb\x3b\x84\x23\x1f\x82\x1f\x21\xe2\ 160 | \x50\x08\x33\xdd\xa2\xb1\x2f\x2f\x4b\x15\x00\x8c\xb1\xb3\x11\xf1\ 161 | \x37\x00\x90\x6f\xcb\xe0\x6b\x44\xb4\x51\x4a\x59\xd1\xcd\x6c\x14\ 162 | \x3b\xb5\xd0\x14\x11\xc7\xd2\x08\x41\x2a\x00\x70\x5d\xf7\x3d\x8e\ 163 | \xe3\x5c\x4e\x44\xd7\x20\xe2\x51\xc7\xd5\x35\x1f\x05\xea\xb8\x38\ 164 | \xb5\x3f\xb1\x10\x42\x9d\xe6\x69\xf4\xfc\xc2\xb4\x42\x90\x48\x00\ 165 | \x5c\xd7\x55\x47\xd4\x5c\x84\x88\x1f\x41\x44\x75\x40\xe5\xf2\x90\ 166 | \x77\xe8\x7e\x22\xaa\x23\xe2\x14\x11\x4d\x49\x29\x77\x87\xb4\xd7\ 167 | \x2a\x9e\x46\x08\x12\x07\x80\xeb\xba\x9b\x1c\xc7\x89\x75\xc3\x09\ 168 | \x22\xba\x4b\x4a\x79\xbd\x96\xaa\x21\x8d\xd2\x06\x41\x12\x01\x50\ 169 | \x5d\xfc\x26\x75\xf7\x03\xc0\x1a\xdd\x03\xab\x88\xe8\x15\x75\xcc\ 170 | \x9d\xea\x05\x00\x60\x4c\x08\xa1\xce\xf8\x35\x72\xa5\x09\x82\xc4\ 171 | \x01\xd0\xae\xd0\xc8\xc8\xc8\xa9\x43\x43\x43\xea\xf4\xb2\x2b\x9b\ 172 | \xdb\xd2\x2d\xa0\xe2\x0b\x9e\xe7\x6d\x25\xa2\x1d\xb5\x5a\xed\x4f\ 173 | \xa6\xc7\x01\xad\xf5\x4a\x0b\x04\x89\x07\xa0\x35\xa9\x9c\xf3\x6b\ 174 | \x01\xe0\x5b\x00\xe0\x74\x80\xe0\x6e\x21\xc4\xd5\x00\xe0\x19\xb9\ 175 | \xcd\x03\x04\xe9\x03\x04\xa1\x0f\xe0\x4a\x15\x00\x2a\xe7\x8c\x31\ 176 | \x75\x7a\xc9\xb7\xdb\xf2\xbf\x53\x08\xb1\x26\x80\x26\xc6\x8b\x98\ 177 | \x84\x40\xf5\x7c\x85\x42\xa1\x14\xe6\x14\xb6\xd4\x01\x50\x2c\x16\ 178 | \x8f\x2d\x14\x0a\x6a\x9b\xda\xe1\xa6\x9a\x6a\x5f\x9f\x4a\xa5\xf2\ 179 | \x47\xe3\xea\x06\x0c\x98\x64\x08\x52\x07\x80\xdf\x0b\x48\x44\x74\ 180 | \xfd\xf7\xff\x17\xa5\x94\xa7\x06\xd4\xa2\x6f\xc5\x92\x0a\x41\x2a\ 181 | \x01\x70\x5d\x77\x8b\xe3\x38\x87\xa7\x7e\x89\xe8\x1e\x29\xe5\xe6\ 182 | \xbe\x29\x1b\x22\x70\x12\x21\x48\x25\x00\xa5\x52\x69\x05\x11\x3d\ 183 | \xa7\x72\xef\x79\xde\x68\xb5\x5a\xfd\x55\x08\x1d\xfa\x5a\x34\x69\ 184 | \x10\xa4\x12\x00\xa5\x20\xe7\xfc\x00\x11\x2d\x99\x99\x99\x39\xa1\ 185 | \x5e\xaf\xab\x83\x28\x53\x73\x25\x09\x82\xd4\x02\xc0\x18\xbb\x1f\ 186 | \x11\x4f\x17\x42\xac\x4a\x8d\xf2\x2d\x15\x4d\x0a\x04\xa9\x05\xe0\ 187 | \xdc\x73\xcf\x1d\xce\xe7\xf3\xf9\xb8\x8f\xa4\x37\x09\x53\x12\x20\ 188 | \x48\x2d\x00\x26\x85\xea\x65\xac\x7e\x43\x60\x01\xe8\xa5\xba\x01\ 189 | \x7d\xf7\x13\x02\x0b\x40\x40\x91\x7a\x5d\xac\x5f\x10\x58\x00\x7a\ 190 | \xad\x6c\x08\xff\xfd\x80\xc0\x02\x10\x42\x20\x13\x45\x19\x63\x1b\ 191 | \x11\xd1\xc8\xbc\x06\x11\x3d\x62\x01\x30\xa1\x6a\xc8\x18\x26\x7a\ 192 | \x02\x22\x9a\x45\xc4\x92\x05\x20\xa4\x38\xa6\x8a\xf7\x12\x82\xa6\ 193 | \xf8\x42\x88\x9d\x16\x00\x53\x8a\x6a\xc4\xe9\x05\x04\xad\xe2\xab\ 194 | \x2a\x59\x00\x34\x84\x31\x69\x12\x27\x04\xed\xe2\x5b\x00\x4c\x2a\ 195 | \x19\x21\x56\x1c\x10\x74\x12\xdf\x02\x10\x41\x14\xd3\xa6\x51\x20\ 196 | \x98\x4f\x7c\x0b\x80\x69\x15\x23\xc6\xd3\x81\x60\x21\xf1\x2d\x00\ 197 | \x11\x05\xe9\x87\x79\x18\x08\xba\x89\x6f\x01\xe8\x87\x82\x31\xc4\ 198 | \x0c\x02\x41\x10\xf1\x2d\x00\x31\x88\xd1\x2f\x17\x0b\x41\x10\x54\ 199 | \x7c\x0b\x40\xbf\xd4\x8b\x29\x6e\x27\x08\xc2\x88\x6f\x01\x88\x49\ 200 | \x88\x7e\xba\x69\x85\x20\xac\xf8\x16\x80\x7e\x2a\x17\x63\xec\x52\ 201 | \xa9\xb4\xc1\xf3\xbc\x9f\x02\xc0\x06\x29\xe5\x8e\x30\xae\xed\x4c\ 202 | \x60\x98\x6c\x25\xb8\x6c\xb9\x5c\x5e\xaa\xb3\x4d\x8e\x05\x20\xc1\ 203 | \xa2\x9a\xa8\x9a\x05\xc0\x44\x96\x13\x1c\xc3\x02\x90\x60\x71\x4c\ 204 | \x54\xcd\x02\x60\x22\xcb\x09\x8e\x61\x01\x48\xb0\x38\x26\xaa\x66\ 205 | \x01\x30\x91\xe5\x04\xc7\xb0\x00\x24\x58\x1c\x13\x55\xfb\x3f\x5e\ 206 | \xdc\xa5\x83\xe1\xdb\x27\x05\x00\x00\x00\x00\x49\x45\x4e\x44\xae\ 207 | \x42\x60\x82\ 208 | " 209 | 210 | qt_resource_name = b"\ 211 | \x00\x07\ 212 | \x07\x3b\xe0\xb3\ 213 | \x00\x70\ 214 | \x00\x6c\x00\x75\x00\x67\x00\x69\x00\x6e\x00\x73\ 215 | \x00\x0a\ 216 | \x0f\x98\xbb\xe4\ 217 | \x00\x6d\ 218 | \x00\x61\x00\x67\x00\x69\x00\x63\x00\x5f\x00\x77\x00\x61\x00\x6e\x00\x64\ 219 | \x00\x08\ 220 | \x0a\x61\x5a\xa7\ 221 | \x00\x69\ 222 | \x00\x63\x00\x6f\x00\x6e\x00\x2e\x00\x70\x00\x6e\x00\x67\ 223 | " 224 | 225 | qt_resource_struct_v1 = b"\ 226 | \x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x01\ 227 | \x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x02\ 228 | \x00\x00\x00\x14\x00\x02\x00\x00\x00\x01\x00\x00\x00\x03\ 229 | \x00\x00\x00\x2e\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\ 230 | " 231 | 232 | qt_resource_struct_v2 = b"\ 233 | \x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x01\ 234 | \x00\x00\x00\x00\x00\x00\x00\x00\ 235 | \x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x02\ 236 | \x00\x00\x00\x00\x00\x00\x00\x00\ 237 | \x00\x00\x00\x14\x00\x02\x00\x00\x00\x01\x00\x00\x00\x03\ 238 | \x00\x00\x00\x00\x00\x00\x00\x00\ 239 | \x00\x00\x00\x2e\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\ 240 | \x00\x00\x01\x6c\x4d\x2b\xaa\x38\ 241 | " 242 | 243 | qt_version = QtCore.qVersion().split('.') 244 | if qt_version < ['5', '8', '0']: 245 | rcc_version = 1 246 | qt_resource_struct = qt_resource_struct_v1 247 | else: 248 | rcc_version = 2 249 | qt_resource_struct = qt_resource_struct_v2 250 | 251 | def qInitResources(): 252 | QtCore.qRegisterResourceData(rcc_version, qt_resource_struct, qt_resource_name, qt_resource_data) 253 | 254 | def qCleanupResources(): 255 | QtCore.qUnregisterResourceData(rcc_version, qt_resource_struct, qt_resource_name, qt_resource_data) 256 | 257 | qInitResources() 258 | -------------------------------------------------------------------------------- /resources.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | icon.png 4 | 5 | 6 | --------------------------------------------------------------------------------