조현아

faa settings for vm

Showing 1000 changed files with 4866 additions and 0 deletions

Too many changes to show.

To preserve performance only 1000 of 1000+ files are displayed.

1 +<?xml version="1.0" encoding="UTF-8"?>
2 +<module type="PYTHON_MODULE" version="4">
3 + <component name="NewModuleRootManager">
4 + <content url="file://$MODULE_DIR$" />
5 + <orderEntry type="jdk" jdkName="Python 3.6 (FAA2)" jdkType="Python SDK" />
6 + <orderEntry type="sourceFolder" forTests="false" />
7 + </component>
8 + <component name="TestRunnerService">
9 + <option name="PROJECT_TEST_RUNNER" value="Unittests" />
10 + </component>
11 +</module>
...\ No newline at end of file ...\ No newline at end of file
1 +<?xml version="1.0" encoding="UTF-8"?>
2 +<project version="4">
3 + <component name="Encoding" addBOMForNewFiles="with NO BOM" />
4 +</project>
...\ No newline at end of file ...\ No newline at end of file
1 +<?xml version="1.0" encoding="UTF-8"?>
2 +<project version="4">
3 + <component name="JavaScriptSettings">
4 + <option name="languageLevel" value="ES6" />
5 + </component>
6 + <component name="ProjectRootManager" version="2" project-jdk-name="Python 3.6 (FAA2)" project-jdk-type="Python SDK" />
7 +</project>
...\ No newline at end of file ...\ No newline at end of file
1 +<?xml version="1.0" encoding="UTF-8"?>
2 +<project version="4">
3 + <component name="ProjectModuleManager">
4 + <modules>
5 + <module fileurl="file://$PROJECT_DIR$/.idea/FAA2.iml" filepath="$PROJECT_DIR$/.idea/FAA2.iml" />
6 + </modules>
7 + </component>
8 +</project>
...\ No newline at end of file ...\ No newline at end of file
1 +<?xml version="1.0" encoding="UTF-8"?>
2 +<project version="4">
3 + <component name="VcsDirectoryMappings">
4 + <mapping directory="$PROJECT_DIR$/../.." vcs="Git" />
5 + </component>
6 +</project>
...\ No newline at end of file ...\ No newline at end of file
1 +<?xml version="1.0" encoding="UTF-8"?>
2 +<project version="4">
3 + <component name="ChangeListManager">
4 + <list default="true" id="ecac36b2-5eb8-4bdd-ae5c-1971962221d8" name="Default Changelist" comment="">
5 + <change beforePath="$PROJECT_DIR$/../.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/../.idea/workspace.xml" afterDir="false" />
6 + <change beforePath="$PROJECT_DIR$/fast_auto_augment.py" beforeDir="false" afterPath="$PROJECT_DIR$/fast_auto_augment.py" afterDir="false" />
7 + <change beforePath="$PROJECT_DIR$/requirements.txt" beforeDir="false" afterPath="$PROJECT_DIR$/requirements.txt" afterDir="false" />
8 + <change beforePath="$PROJECT_DIR$/train.py" beforeDir="false" afterPath="$PROJECT_DIR$/train.py" afterDir="false" />
9 + <change beforePath="$PROJECT_DIR$/transforms.py" beforeDir="false" afterPath="$PROJECT_DIR$/transforms.py" afterDir="false" />
10 + <change beforePath="$PROJECT_DIR$/utils.py" beforeDir="false" afterPath="$PROJECT_DIR$/utils.py" afterDir="false" />
11 + <change beforePath="$PROJECT_DIR$/../getframe.m" beforeDir="false" afterPath="$PROJECT_DIR$/../getframe.m" afterDir="false" />
12 + </list>
13 + <option name="EXCLUDED_CONVERTED_TO_IGNORED" value="true" />
14 + <option name="SHOW_DIALOG" value="false" />
15 + <option name="HIGHLIGHT_CONFLICTS" value="true" />
16 + <option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
17 + <option name="LAST_RESOLUTION" value="IGNORE" />
18 + </component>
19 + <component name="FileEditorManager">
20 + <leaf>
21 + <file pinned="false" current-in-tab="true">
22 + <entry file="file://$PROJECT_DIR$/requirements.txt">
23 + <provider selected="true" editor-type-id="text-editor">
24 + <state relative-caret-position="176">
25 + <caret line="8" lean-forward="true" selection-start-line="8" selection-end-line="8" />
26 + </state>
27 + </provider>
28 + </entry>
29 + </file>
30 + </leaf>
31 + </component>
32 + <component name="Git.Settings">
33 + <option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$/../.." />
34 + </component>
35 + <component name="IdeDocumentHistory">
36 + <option name="CHANGED_PATHS">
37 + <list>
38 + <option value="$PROJECT_DIR$/requirements.txt" />
39 + </list>
40 + </option>
41 + </component>
42 + <component name="ProjectFrameBounds" extendedState="6">
43 + <option name="x" value="-9" />
44 + <option name="width" value="1825" />
45 + <option name="height" value="1040" />
46 + </component>
47 + <component name="ProjectLevelVcsManager" settingsEditedManually="true" />
48 + <component name="ProjectView">
49 + <navigator proportions="" version="1">
50 + <foldersAlwaysOnTop value="true" />
51 + </navigator>
52 + <panes>
53 + <pane id="ProjectPane">
54 + <subPane>
55 + <expand>
56 + <path>
57 + <item name="FAA2" type="b2602c69:ProjectViewProjectNode" />
58 + <item name="FAA2" type="462c0819:PsiDirectoryNode" />
59 + </path>
60 + </expand>
61 + <select />
62 + </subPane>
63 + </pane>
64 + <pane id="Scope" />
65 + </panes>
66 + </component>
67 + <component name="PropertiesComponent">
68 + <property name="WebServerToolWindowFactoryState" value="false" />
69 + <property name="last_opened_file_path" value="$USER_HOME$/Anaconda3/Scripts/conda.exe" />
70 + <property name="nodejs_interpreter_path.stuck_in_default_project" value="undefined stuck path" />
71 + <property name="nodejs_npm_path_reset_for_default_project" value="true" />
72 + <property name="settings.editor.selected.configurable" value="web.server" />
73 + </component>
74 + <component name="RunDashboard">
75 + <option name="ruleStates">
76 + <list>
77 + <RuleState>
78 + <option name="name" value="ConfigurationTypeDashboardGroupingRule" />
79 + </RuleState>
80 + <RuleState>
81 + <option name="name" value="StatusDashboardGroupingRule" />
82 + </RuleState>
83 + </list>
84 + </option>
85 + </component>
86 + <component name="SvnConfiguration">
87 + <configuration />
88 + </component>
89 + <component name="TaskManager">
90 + <task active="true" id="Default" summary="Default task">
91 + <changelist id="ecac36b2-5eb8-4bdd-ae5c-1971962221d8" name="Default Changelist" comment="" />
92 + <created>1585929097107</created>
93 + <option name="number" value="Default" />
94 + <option name="presentableId" value="Default" />
95 + <updated>1585929097107</updated>
96 + <workItem from="1585929098868" duration="1531000" />
97 + </task>
98 + <servers />
99 + </component>
100 + <component name="TimeTrackingManager">
101 + <option name="totallyTimeSpent" value="1531000" />
102 + </component>
103 + <component name="ToolWindowManager">
104 + <frame x="-7" y="-7" width="1550" height="838" extended-state="6" />
105 + <layout>
106 + <window_info id="Favorites" side_tool="true" />
107 + <window_info active="true" content_ui="combo" id="Project" order="0" visible="true" weight="0.23489933" />
108 + <window_info id="Structure" order="1" side_tool="true" weight="0.25" />
109 + <window_info anchor="bottom" id="Docker" show_stripe_button="false" />
110 + <window_info anchor="bottom" id="Database Changes" />
111 + <window_info anchor="bottom" id="Version Control" />
112 + <window_info anchor="bottom" id="Python Console" />
113 + <window_info anchor="bottom" id="Terminal" weight="0.6028369" />
114 + <window_info anchor="bottom" id="Event Log" side_tool="true" />
115 + <window_info anchor="bottom" id="Message" order="0" />
116 + <window_info anchor="bottom" id="Find" order="1" />
117 + <window_info anchor="bottom" id="Run" order="2" />
118 + <window_info anchor="bottom" id="Debug" order="3" weight="0.4" />
119 + <window_info anchor="bottom" id="Cvs" order="4" weight="0.25" />
120 + <window_info anchor="bottom" id="Inspection" order="5" weight="0.4" />
121 + <window_info anchor="bottom" id="TODO" order="6" />
122 + <window_info anchor="right" id="SciView" />
123 + <window_info anchor="right" id="Database" />
124 + <window_info anchor="right" id="Commander" internal_type="SLIDING" order="0" type="SLIDING" weight="0.4" />
125 + <window_info anchor="right" id="Ant Build" order="1" weight="0.25" />
126 + <window_info anchor="right" content_ui="combo" id="Hierarchy" order="2" weight="0.25" />
127 + </layout>
128 + </component>
129 + <component name="TypeScriptGeneratedFilesManager">
130 + <option name="version" value="1" />
131 + </component>
132 + <component name="editorHistoryManager">
133 + <entry file="file://$PROJECT_DIR$/requirements.txt">
134 + <provider selected="true" editor-type-id="text-editor">
135 + <state relative-caret-position="176">
136 + <caret line="8" lean-forward="true" selection-start-line="8" selection-end-line="8" />
137 + </state>
138 + </provider>
139 + </entry>
140 + </component>
141 +</project>
...\ No newline at end of file ...\ No newline at end of file
1 +{
2 + "python.pythonPath": "C:\\Users\\User\\Anaconda3\\python.exe"
3 +}
...\ No newline at end of file ...\ No newline at end of file
1 +Copyright 2007, 2008 The Python Markdown Project (v. 1.7 and later)
2 +Copyright 2004, 2005, 2006 Yuri Takhteyev (v. 0.2-1.6b)
3 +Copyright 2004 Manfred Stienstra (the original version)
4 +
5 +All rights reserved.
6 +
7 +Redistribution and use in source and binary forms, with or without
8 +modification, are permitted provided that the following conditions are met:
9 +
10 +* Redistributions of source code must retain the above copyright
11 + notice, this list of conditions and the following disclaimer.
12 +* Redistributions in binary form must reproduce the above copyright
13 + notice, this list of conditions and the following disclaimer in the
14 + documentation and/or other materials provided with the distribution.
15 +* Neither the name of the Python Markdown Project nor the
16 + names of its contributors may be used to endorse or promote products
17 + derived from this software without specific prior written permission.
18 +
19 +THIS SOFTWARE IS PROVIDED BY THE PYTHON MARKDOWN PROJECT ''AS IS'' AND ANY
20 +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 +DISCLAIMED. IN NO EVENT SHALL ANY CONTRIBUTORS TO THE PYTHON MARKDOWN PROJECT
23 +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 +POSSIBILITY OF SUCH DAMAGE.
1 +Metadata-Version: 2.1
2 +Name: Markdown
3 +Version: 3.2.1
4 +Summary: Python implementation of Markdown.
5 +Home-page: https://Python-Markdown.github.io/
6 +Author: Manfred Stienstra, Yuri takhteyev and Waylan limberg
7 +Author-email: waylan.limberg@icloud.com
8 +Maintainer: Waylan Limberg
9 +Maintainer-email: waylan.limberg@icloud.com
10 +License: BSD License
11 +Download-URL: http://pypi.python.org/packages/source/M/Markdown/Markdown-3.2.1-py2.py3-none-any.whl
12 +Platform: UNKNOWN
13 +Classifier: Development Status :: 5 - Production/Stable
14 +Classifier: License :: OSI Approved :: BSD License
15 +Classifier: Operating System :: OS Independent
16 +Classifier: Programming Language :: Python
17 +Classifier: Programming Language :: Python :: 3
18 +Classifier: Programming Language :: Python :: 3.5
19 +Classifier: Programming Language :: Python :: 3.6
20 +Classifier: Programming Language :: Python :: 3.7
21 +Classifier: Programming Language :: Python :: 3.8
22 +Classifier: Programming Language :: Python :: 3 :: Only
23 +Classifier: Programming Language :: Python :: Implementation :: CPython
24 +Classifier: Programming Language :: Python :: Implementation :: PyPy
25 +Classifier: Topic :: Communications :: Email :: Filters
26 +Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content :: CGI Tools/Libraries
27 +Classifier: Topic :: Internet :: WWW/HTTP :: Site Management
28 +Classifier: Topic :: Software Development :: Documentation
29 +Classifier: Topic :: Software Development :: Libraries :: Python Modules
30 +Classifier: Topic :: Text Processing :: Filters
31 +Classifier: Topic :: Text Processing :: Markup :: HTML
32 +Requires-Python: >=3.5
33 +Requires-Dist: setuptools (>=36)
34 +Provides-Extra: testing
35 +Requires-Dist: coverage ; extra == 'testing'
36 +Requires-Dist: pyyaml ; extra == 'testing'
37 +
38 +
39 +This is a Python implementation of John Gruber's Markdown_.
40 +It is almost completely compliant with the reference implementation,
41 +though there are a few known issues. See Features_ for information
42 +on what exactly is supported and what is not. Additional features are
43 +supported by the `Available Extensions`_.
44 +
45 +.. _Markdown: https://daringfireball.net/projects/markdown/
46 +.. _Features: https://Python-Markdown.github.io#features
47 +.. _`Available Extensions`: https://Python-Markdown.github.io/extensions/
48 +
49 +Support
50 +=======
51 +
52 +You may report bugs, ask for help, and discuss various other issues on
53 +the `bug tracker`_.
54 +
55 +.. _`bug tracker`: https://github.com/Python-Markdown/markdown/issues
56 +
57 +
1 +../../Scripts/markdown_py.exe,sha256=xcQRheiF218v5xGonxUh_TeNVUrb4yPs3E0DTOZZuAA,106376
2 +Markdown-3.2.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
3 +Markdown-3.2.1.dist-info/LICENSE.md,sha256=bxGTy2NHGOZcOlN9biXr1hSCDsDvaTz8EiSBEmONZNo,1645
4 +Markdown-3.2.1.dist-info/METADATA,sha256=PK6UzXb9yL09qZJH7SCqZd6-mj8keovCmxQLt89NlEQ,2383
5 +Markdown-3.2.1.dist-info/RECORD,,
6 +Markdown-3.2.1.dist-info/WHEEL,sha256=h_aVn5OB2IERUjMbi2pucmR_zzWJtk303YXvhh60NJ8,110
7 +Markdown-3.2.1.dist-info/entry_points.txt,sha256=j4jiKg-iwZGImvi8OzotZePWoFbJJ4GrfzDqH03u3SQ,1103
8 +Markdown-3.2.1.dist-info/top_level.txt,sha256=IAxs8x618RXoH1uCqeLLxXsDefJvE_mIibr_M4sOlyk,9
9 +markdown/__init__.py,sha256=002-LuHviYzROW2rg_gBGai81nMouUNO9UFj5nSsTSk,2065
10 +markdown/__main__.py,sha256=MpVK3zlwQ-4AzDzZmIScPB90PpunMGVgS5KBmJuHYTw,5802
11 +markdown/__meta__.py,sha256=xhmwLb0Eb6kfiapdM21pCb80lyVEl8hxv8Re_X6wsI0,1837
12 +markdown/__pycache__/__init__.cpython-37.pyc,,
13 +markdown/__pycache__/__main__.cpython-37.pyc,,
14 +markdown/__pycache__/__meta__.cpython-37.pyc,,
15 +markdown/__pycache__/blockparser.cpython-37.pyc,,
16 +markdown/__pycache__/blockprocessors.cpython-37.pyc,,
17 +markdown/__pycache__/core.cpython-37.pyc,,
18 +markdown/__pycache__/inlinepatterns.cpython-37.pyc,,
19 +markdown/__pycache__/pep562.cpython-37.pyc,,
20 +markdown/__pycache__/postprocessors.cpython-37.pyc,,
21 +markdown/__pycache__/preprocessors.cpython-37.pyc,,
22 +markdown/__pycache__/serializers.cpython-37.pyc,,
23 +markdown/__pycache__/test_tools.cpython-37.pyc,,
24 +markdown/__pycache__/treeprocessors.cpython-37.pyc,,
25 +markdown/__pycache__/util.cpython-37.pyc,,
26 +markdown/blockparser.py,sha256=JpBhOokOoBUGCXolftOc5m1hPcR2y9s9hVd9WSuhHzo,4285
27 +markdown/blockprocessors.py,sha256=l4gmkAN9b2L340EX0gm24EyWS7UzBviPqX6wYrcgEco,23736
28 +markdown/core.py,sha256=JLR5hIMwWSeIHRQhTzAymB3QUD3gHCdITFvmuuCpIcA,15360
29 +markdown/extensions/__init__.py,sha256=6kUSgoqDT4gGUVsqf7F9oQD_jA0RJCbX5EK3JVo8iQE,3517
30 +markdown/extensions/__pycache__/__init__.cpython-37.pyc,,
31 +markdown/extensions/__pycache__/abbr.cpython-37.pyc,,
32 +markdown/extensions/__pycache__/admonition.cpython-37.pyc,,
33 +markdown/extensions/__pycache__/attr_list.cpython-37.pyc,,
34 +markdown/extensions/__pycache__/codehilite.cpython-37.pyc,,
35 +markdown/extensions/__pycache__/def_list.cpython-37.pyc,,
36 +markdown/extensions/__pycache__/extra.cpython-37.pyc,,
37 +markdown/extensions/__pycache__/fenced_code.cpython-37.pyc,,
38 +markdown/extensions/__pycache__/footnotes.cpython-37.pyc,,
39 +markdown/extensions/__pycache__/legacy_attrs.cpython-37.pyc,,
40 +markdown/extensions/__pycache__/legacy_em.cpython-37.pyc,,
41 +markdown/extensions/__pycache__/md_in_html.cpython-37.pyc,,
42 +markdown/extensions/__pycache__/meta.cpython-37.pyc,,
43 +markdown/extensions/__pycache__/nl2br.cpython-37.pyc,,
44 +markdown/extensions/__pycache__/sane_lists.cpython-37.pyc,,
45 +markdown/extensions/__pycache__/smarty.cpython-37.pyc,,
46 +markdown/extensions/__pycache__/tables.cpython-37.pyc,,
47 +markdown/extensions/__pycache__/toc.cpython-37.pyc,,
48 +markdown/extensions/__pycache__/wikilinks.cpython-37.pyc,,
49 +markdown/extensions/abbr.py,sha256=pqp2HnOR2giT-iYKyqtsp2_eUOWBR0j_hUfjvUV5c88,2916
50 +markdown/extensions/admonition.py,sha256=HWHHjuYZPAPOg5X8hbpDuSbw8gB6k0odw8GuTT1v_N4,3124
51 +markdown/extensions/attr_list.py,sha256=m9a1H-S33rV2twtlFYuoxSiCAf22ndU5tziSzNF2dNg,6003
52 +markdown/extensions/codehilite.py,sha256=rVZVOIjp2KEIZsnz90mX6E2_xnwVPQZpVVQVJMuMVU0,9834
53 +markdown/extensions/def_list.py,sha256=iqRXAEl2XnyF415afCxihAgOmEUOK1hIuBPIK1k7Tzo,3521
54 +markdown/extensions/extra.py,sha256=udRN8OvSWcq3UwkPygvsFl1RlCVtCJ-ARVg2IwVH6VY,1831
55 +markdown/extensions/fenced_code.py,sha256=dww9rDu2kQtkoTpjn9BBgeGCTNdE1bMPJ2wgR6695iM,3897
56 +markdown/extensions/footnotes.py,sha256=a9sb8RoKqFU8p8ZhpTObrn_Uek0hbyPFVGYpRaEDXaw,15339
57 +markdown/extensions/legacy_attrs.py,sha256=2EaVQkxQoNnP8_lMPvGRBdNda8L4weUQroiyEuVdS-w,2547
58 +markdown/extensions/legacy_em.py,sha256=9ZMGCTrFh01eiOpnFjS0jVkqgYXiTzCGn-eNvYcvObg,1579
59 +markdown/extensions/md_in_html.py,sha256=ohSiGcgR5yBqusuTs0opbTO_5fq442fqPK-klFd_qaM,4040
60 +markdown/extensions/meta.py,sha256=EUfkzM7l7UpH__Or9K3pl8ldVddwndlCZWA3d712RAE,2331
61 +markdown/extensions/nl2br.py,sha256=wAqTNOuf2L1NzlEvEqoID70n9y-aiYaGLkuyQk3CD0w,783
62 +markdown/extensions/sane_lists.py,sha256=ZQmCf-247KBexVG0fc62nDvokGkV6W1uavYbieNKSG4,1505
63 +markdown/extensions/smarty.py,sha256=0padzkVCNACainKw-Xj1S5UfT0125VCTfNejmrCZItA,10238
64 +markdown/extensions/tables.py,sha256=bicFx_wqhnEx6Y_8MJqA56rh71pt5fOe94oiWbvcobY,7685
65 +markdown/extensions/toc.py,sha256=E-d3R4etcM_R2sQyTpKkejRv2NHrHPCvaXK9hUqfK58,13224
66 +markdown/extensions/wikilinks.py,sha256=GkgT9BY7b1-qW--dIwFAhC9V20RoeF13b7CFdw_V21Q,2812
67 +markdown/inlinepatterns.py,sha256=EnYq9aU_Hi1gu5e8dcbUxUu0mRz-pHFV79uGQCYbD5I,29378
68 +markdown/pep562.py,sha256=5UkqT7sb-cQufgbOl_jF-RYUVVHS7VThzlMzR9vrd3I,8917
69 +markdown/postprocessors.py,sha256=25g6qqpJ4kuiq4RBrGz8RA6GMb7ArUi1AN2VDVnR35U,3738
70 +markdown/preprocessors.py,sha256=dsmMVPP2afKAZ0s59_mFidM_mCiNfgdBJ9aVDWu_viE,15323
71 +markdown/serializers.py,sha256=_wQl-iJrPSUEQ4Q1owWYqN9qceVh6TOlAOH_i44BKAQ,6540
72 +markdown/test_tools.py,sha256=zFHFzmtzjfMRroyyli3LY4SP8yLfLf4S7SsU3z7Z1SQ,6823
73 +markdown/treeprocessors.py,sha256=NBaYc9TEGP7TBaN6YRROIqE5Lj-AMoAqp0jN-coGW3Q,15401
74 +markdown/util.py,sha256=0ySktJgYplEV7g6TOOs8fatAS4Fi-6F7iv4D9Vw3g0c,15201
1 +Wheel-Version: 1.0
2 +Generator: bdist_wheel (0.33.4)
3 +Root-Is-Purelib: true
4 +Tag: py2-none-any
5 +Tag: py3-none-any
6 +
1 +[console_scripts]
2 +markdown_py = markdown.__main__:run
3 +
4 +[markdown.extensions]
5 +abbr = markdown.extensions.abbr:AbbrExtension
6 +admonition = markdown.extensions.admonition:AdmonitionExtension
7 +attr_list = markdown.extensions.attr_list:AttrListExtension
8 +codehilite = markdown.extensions.codehilite:CodeHiliteExtension
9 +def_list = markdown.extensions.def_list:DefListExtension
10 +extra = markdown.extensions.extra:ExtraExtension
11 +fenced_code = markdown.extensions.fenced_code:FencedCodeExtension
12 +footnotes = markdown.extensions.footnotes:FootnoteExtension
13 +legacy_attrs = markdown.extensions.legacy_attrs:LegacyAttrExtension
14 +legacy_em = markdown.extensions.legacy_em:LegacyEmExtension
15 +md_in_html = markdown.extensions.md_in_html:MarkdownInHtmlExtension
16 +meta = markdown.extensions.meta:MetaExtension
17 +nl2br = markdown.extensions.nl2br:Nl2BrExtension
18 +sane_lists = markdown.extensions.sane_lists:SaneListExtension
19 +smarty = markdown.extensions.smarty:SmartyExtension
20 +tables = markdown.extensions.tables:TableExtension
21 +toc = markdown.extensions.toc:TocExtension
22 +wikilinks = markdown.extensions.wikilinks:WikiLinkExtension
23 +
1 +#
2 +# The Python Imaging Library
3 +# $Id$
4 +#
5 +# bitmap distribution font (bdf) file parser
6 +#
7 +# history:
8 +# 1996-05-16 fl created (as bdf2pil)
9 +# 1997-08-25 fl converted to FontFile driver
10 +# 2001-05-25 fl removed bogus __init__ call
11 +# 2002-11-20 fl robustification (from Kevin Cazabon, Dmitry Vasiliev)
12 +# 2003-04-22 fl more robustification (from Graham Dumpleton)
13 +#
14 +# Copyright (c) 1997-2003 by Secret Labs AB.
15 +# Copyright (c) 1997-2003 by Fredrik Lundh.
16 +#
17 +# See the README file for information on usage and redistribution.
18 +#
19 +
20 +from __future__ import print_function
21 +
22 +from . import FontFile, Image
23 +
24 +# --------------------------------------------------------------------
25 +# parse X Bitmap Distribution Format (BDF)
26 +# --------------------------------------------------------------------
27 +
28 +bdf_slant = {
29 + "R": "Roman",
30 + "I": "Italic",
31 + "O": "Oblique",
32 + "RI": "Reverse Italic",
33 + "RO": "Reverse Oblique",
34 + "OT": "Other",
35 +}
36 +
37 +bdf_spacing = {"P": "Proportional", "M": "Monospaced", "C": "Cell"}
38 +
39 +
40 +def bdf_char(f):
41 + # skip to STARTCHAR
42 + while True:
43 + s = f.readline()
44 + if not s:
45 + return None
46 + if s[:9] == b"STARTCHAR":
47 + break
48 + id = s[9:].strip().decode("ascii")
49 +
50 + # load symbol properties
51 + props = {}
52 + while True:
53 + s = f.readline()
54 + if not s or s[:6] == b"BITMAP":
55 + break
56 + i = s.find(b" ")
57 + props[s[:i].decode("ascii")] = s[i + 1 : -1].decode("ascii")
58 +
59 + # load bitmap
60 + bitmap = []
61 + while True:
62 + s = f.readline()
63 + if not s or s[:7] == b"ENDCHAR":
64 + break
65 + bitmap.append(s[:-1])
66 + bitmap = b"".join(bitmap)
67 +
68 + [x, y, l, d] = [int(p) for p in props["BBX"].split()]
69 + [dx, dy] = [int(p) for p in props["DWIDTH"].split()]
70 +
71 + bbox = (dx, dy), (l, -d - y, x + l, -d), (0, 0, x, y)
72 +
73 + try:
74 + im = Image.frombytes("1", (x, y), bitmap, "hex", "1")
75 + except ValueError:
76 + # deal with zero-width characters
77 + im = Image.new("1", (x, y))
78 +
79 + return id, int(props["ENCODING"]), bbox, im
80 +
81 +
82 +##
83 +# Font file plugin for the X11 BDF format.
84 +
85 +
86 +class BdfFontFile(FontFile.FontFile):
87 + def __init__(self, fp):
88 +
89 + FontFile.FontFile.__init__(self)
90 +
91 + s = fp.readline()
92 + if s[:13] != b"STARTFONT 2.1":
93 + raise SyntaxError("not a valid BDF file")
94 +
95 + props = {}
96 + comments = []
97 +
98 + while True:
99 + s = fp.readline()
100 + if not s or s[:13] == b"ENDPROPERTIES":
101 + break
102 + i = s.find(b" ")
103 + props[s[:i].decode("ascii")] = s[i + 1 : -1].decode("ascii")
104 + if s[:i] in [b"COMMENT", b"COPYRIGHT"]:
105 + if s.find(b"LogicalFontDescription") < 0:
106 + comments.append(s[i + 1 : -1].decode("ascii"))
107 +
108 + while True:
109 + c = bdf_char(fp)
110 + if not c:
111 + break
112 + id, ch, (xy, dst, src), im = c
113 + if 0 <= ch < len(self.glyph):
114 + self.glyph[ch] = xy, dst, src, im
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
1 +#
2 +# The Python Imaging Library
3 +# $Id$
4 +#
5 +# BUFR stub adapter
6 +#
7 +# Copyright (c) 1996-2003 by Fredrik Lundh
8 +#
9 +# See the README file for information on usage and redistribution.
10 +#
11 +
12 +from . import Image, ImageFile
13 +
14 +_handler = None
15 +
16 +
17 +def register_handler(handler):
18 + """
19 + Install application-specific BUFR image handler.
20 +
21 + :param handler: Handler object.
22 + """
23 + global _handler
24 + _handler = handler
25 +
26 +
27 +# --------------------------------------------------------------------
28 +# Image adapter
29 +
30 +
31 +def _accept(prefix):
32 + return prefix[:4] == b"BUFR" or prefix[:4] == b"ZCZC"
33 +
34 +
35 +class BufrStubImageFile(ImageFile.StubImageFile):
36 +
37 + format = "BUFR"
38 + format_description = "BUFR"
39 +
40 + def _open(self):
41 +
42 + offset = self.fp.tell()
43 +
44 + if not _accept(self.fp.read(4)):
45 + raise SyntaxError("Not a BUFR file")
46 +
47 + self.fp.seek(offset)
48 +
49 + # make something up
50 + self.mode = "F"
51 + self._size = 1, 1
52 +
53 + loader = self._load()
54 + if loader:
55 + loader.open(self)
56 +
57 + def _load(self):
58 + return _handler
59 +
60 +
61 +def _save(im, fp, filename):
62 + if _handler is None or not hasattr("_handler", "save"):
63 + raise IOError("BUFR save handler not installed")
64 + _handler.save(im, fp, filename)
65 +
66 +
67 +# --------------------------------------------------------------------
68 +# Registry
69 +
70 +Image.register_open(BufrStubImageFile.format, BufrStubImageFile, _accept)
71 +Image.register_save(BufrStubImageFile.format, _save)
72 +
73 +Image.register_extension(BufrStubImageFile.format, ".bufr")
1 +#
2 +# The Python Imaging Library.
3 +# $Id$
4 +#
5 +# a class to read from a container file
6 +#
7 +# History:
8 +# 1995-06-18 fl Created
9 +# 1995-09-07 fl Added readline(), readlines()
10 +#
11 +# Copyright (c) 1997-2001 by Secret Labs AB
12 +# Copyright (c) 1995 by Fredrik Lundh
13 +#
14 +# See the README file for information on usage and redistribution.
15 +#
16 +
17 +##
18 +# A file object that provides read access to a part of an existing
19 +# file (for example a TAR file).
20 +
21 +import io
22 +
23 +
24 +class ContainerIO(object):
25 + def __init__(self, file, offset, length):
26 + """
27 + Create file object.
28 +
29 + :param file: Existing file.
30 + :param offset: Start of region, in bytes.
31 + :param length: Size of region, in bytes.
32 + """
33 + self.fh = file
34 + self.pos = 0
35 + self.offset = offset
36 + self.length = length
37 + self.fh.seek(offset)
38 +
39 + ##
40 + # Always false.
41 +
42 + def isatty(self):
43 + return False
44 +
45 + def seek(self, offset, mode=io.SEEK_SET):
46 + """
47 + Move file pointer.
48 +
49 + :param offset: Offset in bytes.
50 + :param mode: Starting position. Use 0 for beginning of region, 1
51 + for current offset, and 2 for end of region. You cannot move
52 + the pointer outside the defined region.
53 + """
54 + if mode == 1:
55 + self.pos = self.pos + offset
56 + elif mode == 2:
57 + self.pos = self.length + offset
58 + else:
59 + self.pos = offset
60 + # clamp
61 + self.pos = max(0, min(self.pos, self.length))
62 + self.fh.seek(self.offset + self.pos)
63 +
64 + def tell(self):
65 + """
66 + Get current file pointer.
67 +
68 + :returns: Offset from start of region, in bytes.
69 + """
70 + return self.pos
71 +
72 + def read(self, n=0):
73 + """
74 + Read data.
75 +
76 + :param n: Number of bytes to read. If omitted or zero,
77 + read until end of region.
78 + :returns: An 8-bit string.
79 + """
80 + if n:
81 + n = min(n, self.length - self.pos)
82 + else:
83 + n = self.length - self.pos
84 + if not n: # EOF
85 + return ""
86 + self.pos = self.pos + n
87 + return self.fh.read(n)
88 +
89 + def readline(self):
90 + """
91 + Read a line of text.
92 +
93 + :returns: An 8-bit string.
94 + """
95 + s = ""
96 + while True:
97 + c = self.read(1)
98 + if not c:
99 + break
100 + s = s + c
101 + if c == "\n":
102 + break
103 + return s
104 +
105 + def readlines(self):
106 + """
107 + Read multiple lines of text.
108 +
109 + :returns: A list of 8-bit strings.
110 + """
111 + lines = []
112 + while True:
113 + s = self.readline()
114 + if not s:
115 + break
116 + lines.append(s)
117 + return lines
1 +#
2 +# The Python Imaging Library.
3 +# $Id$
4 +#
5 +# Windows Cursor support for PIL
6 +#
7 +# notes:
8 +# uses BmpImagePlugin.py to read the bitmap data.
9 +#
10 +# history:
11 +# 96-05-27 fl Created
12 +#
13 +# Copyright (c) Secret Labs AB 1997.
14 +# Copyright (c) Fredrik Lundh 1996.
15 +#
16 +# See the README file for information on usage and redistribution.
17 +#
18 +
19 +from __future__ import print_function
20 +
21 +from . import BmpImagePlugin, Image
22 +from ._binary import i8, i16le as i16, i32le as i32
23 +
24 +# __version__ is deprecated and will be removed in a future version. Use
25 +# PIL.__version__ instead.
26 +__version__ = "0.1"
27 +
28 +#
29 +# --------------------------------------------------------------------
30 +
31 +
32 +def _accept(prefix):
33 + return prefix[:4] == b"\0\0\2\0"
34 +
35 +
36 +##
37 +# Image plugin for Windows Cursor files.
38 +
39 +
40 +class CurImageFile(BmpImagePlugin.BmpImageFile):
41 +
42 + format = "CUR"
43 + format_description = "Windows Cursor"
44 +
45 + def _open(self):
46 +
47 + offset = self.fp.tell()
48 +
49 + # check magic
50 + s = self.fp.read(6)
51 + if not _accept(s):
52 + raise SyntaxError("not a CUR file")
53 +
54 + # pick the largest cursor in the file
55 + m = b""
56 + for i in range(i16(s[4:])):
57 + s = self.fp.read(16)
58 + if not m:
59 + m = s
60 + elif i8(s[0]) > i8(m[0]) and i8(s[1]) > i8(m[1]):
61 + m = s
62 + if not m:
63 + raise TypeError("No cursors were found")
64 +
65 + # load as bitmap
66 + self._bitmap(i32(m[12:]) + offset)
67 +
68 + # patch up the bitmap height
69 + self._size = self.size[0], self.size[1] // 2
70 + d, e, o, a = self.tile[0]
71 + self.tile[0] = d, (0, 0) + self.size, o, a
72 +
73 + return
74 +
75 +
76 +#
77 +# --------------------------------------------------------------------
78 +
79 +Image.register_open(CurImageFile.format, CurImageFile, _accept)
80 +
81 +Image.register_extension(CurImageFile.format, ".cur")
1 +#
2 +# The Python Imaging Library.
3 +# $Id$
4 +#
5 +# DCX file handling
6 +#
7 +# DCX is a container file format defined by Intel, commonly used
8 +# for fax applications. Each DCX file consists of a directory
9 +# (a list of file offsets) followed by a set of (usually 1-bit)
10 +# PCX files.
11 +#
12 +# History:
13 +# 1995-09-09 fl Created
14 +# 1996-03-20 fl Properly derived from PcxImageFile.
15 +# 1998-07-15 fl Renamed offset attribute to avoid name clash
16 +# 2002-07-30 fl Fixed file handling
17 +#
18 +# Copyright (c) 1997-98 by Secret Labs AB.
19 +# Copyright (c) 1995-96 by Fredrik Lundh.
20 +#
21 +# See the README file for information on usage and redistribution.
22 +#
23 +
24 +from . import Image
25 +from ._binary import i32le as i32
26 +from .PcxImagePlugin import PcxImageFile
27 +
28 +# __version__ is deprecated and will be removed in a future version. Use
29 +# PIL.__version__ instead.
30 +__version__ = "0.2"
31 +
32 +MAGIC = 0x3ADE68B1 # QUIZ: what's this value, then?
33 +
34 +
35 +def _accept(prefix):
36 + return len(prefix) >= 4 and i32(prefix) == MAGIC
37 +
38 +
39 +##
40 +# Image plugin for the Intel DCX format.
41 +
42 +
43 +class DcxImageFile(PcxImageFile):
44 +
45 + format = "DCX"
46 + format_description = "Intel DCX"
47 + _close_exclusive_fp_after_loading = False
48 +
49 + def _open(self):
50 +
51 + # Header
52 + s = self.fp.read(4)
53 + if i32(s) != MAGIC:
54 + raise SyntaxError("not a DCX file")
55 +
56 + # Component directory
57 + self._offset = []
58 + for i in range(1024):
59 + offset = i32(self.fp.read(4))
60 + if not offset:
61 + break
62 + self._offset.append(offset)
63 +
64 + self.__fp = self.fp
65 + self.frame = None
66 + self.seek(0)
67 +
68 + @property
69 + def n_frames(self):
70 + return len(self._offset)
71 +
72 + @property
73 + def is_animated(self):
74 + return len(self._offset) > 1
75 +
76 + def seek(self, frame):
77 + if not self._seek_check(frame):
78 + return
79 + self.frame = frame
80 + self.fp = self.__fp
81 + self.fp.seek(self._offset[frame])
82 + PcxImageFile._open(self)
83 +
84 + def tell(self):
85 + return self.frame
86 +
87 + def _close__fp(self):
88 + try:
89 + if self.__fp != self.fp:
90 + self.__fp.close()
91 + except AttributeError:
92 + pass
93 + finally:
94 + self.__fp = None
95 +
96 +
97 +Image.register_open(DcxImageFile.format, DcxImageFile, _accept)
98 +
99 +Image.register_extension(DcxImageFile.format, ".dcx")
1 +"""
2 +A Pillow loader for .dds files (S3TC-compressed aka DXTC)
3 +Jerome Leclanche <jerome@leclan.ch>
4 +
5 +Documentation:
6 + https://web.archive.org/web/20170802060935/http://oss.sgi.com/projects/ogl-sample/registry/EXT/texture_compression_s3tc.txt
7 +
8 +The contents of this file are hereby released in the public domain (CC0)
9 +Full text of the CC0 license:
10 + https://creativecommons.org/publicdomain/zero/1.0/
11 +"""
12 +
13 +import struct
14 +from io import BytesIO
15 +
16 +from . import Image, ImageFile
17 +
18 +# Magic ("DDS ")
19 +DDS_MAGIC = 0x20534444
20 +
21 +# DDS flags
22 +DDSD_CAPS = 0x1
23 +DDSD_HEIGHT = 0x2
24 +DDSD_WIDTH = 0x4
25 +DDSD_PITCH = 0x8
26 +DDSD_PIXELFORMAT = 0x1000
27 +DDSD_MIPMAPCOUNT = 0x20000
28 +DDSD_LINEARSIZE = 0x80000
29 +DDSD_DEPTH = 0x800000
30 +
31 +# DDS caps
32 +DDSCAPS_COMPLEX = 0x8
33 +DDSCAPS_TEXTURE = 0x1000
34 +DDSCAPS_MIPMAP = 0x400000
35 +
36 +DDSCAPS2_CUBEMAP = 0x200
37 +DDSCAPS2_CUBEMAP_POSITIVEX = 0x400
38 +DDSCAPS2_CUBEMAP_NEGATIVEX = 0x800
39 +DDSCAPS2_CUBEMAP_POSITIVEY = 0x1000
40 +DDSCAPS2_CUBEMAP_NEGATIVEY = 0x2000
41 +DDSCAPS2_CUBEMAP_POSITIVEZ = 0x4000
42 +DDSCAPS2_CUBEMAP_NEGATIVEZ = 0x8000
43 +DDSCAPS2_VOLUME = 0x200000
44 +
45 +# Pixel Format
46 +DDPF_ALPHAPIXELS = 0x1
47 +DDPF_ALPHA = 0x2
48 +DDPF_FOURCC = 0x4
49 +DDPF_PALETTEINDEXED8 = 0x20
50 +DDPF_RGB = 0x40
51 +DDPF_LUMINANCE = 0x20000
52 +
53 +
54 +# dds.h
55 +
56 +DDS_FOURCC = DDPF_FOURCC
57 +DDS_RGB = DDPF_RGB
58 +DDS_RGBA = DDPF_RGB | DDPF_ALPHAPIXELS
59 +DDS_LUMINANCE = DDPF_LUMINANCE
60 +DDS_LUMINANCEA = DDPF_LUMINANCE | DDPF_ALPHAPIXELS
61 +DDS_ALPHA = DDPF_ALPHA
62 +DDS_PAL8 = DDPF_PALETTEINDEXED8
63 +
64 +DDS_HEADER_FLAGS_TEXTURE = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT
65 +DDS_HEADER_FLAGS_MIPMAP = DDSD_MIPMAPCOUNT
66 +DDS_HEADER_FLAGS_VOLUME = DDSD_DEPTH
67 +DDS_HEADER_FLAGS_PITCH = DDSD_PITCH
68 +DDS_HEADER_FLAGS_LINEARSIZE = DDSD_LINEARSIZE
69 +
70 +DDS_HEIGHT = DDSD_HEIGHT
71 +DDS_WIDTH = DDSD_WIDTH
72 +
73 +DDS_SURFACE_FLAGS_TEXTURE = DDSCAPS_TEXTURE
74 +DDS_SURFACE_FLAGS_MIPMAP = DDSCAPS_COMPLEX | DDSCAPS_MIPMAP
75 +DDS_SURFACE_FLAGS_CUBEMAP = DDSCAPS_COMPLEX
76 +
77 +DDS_CUBEMAP_POSITIVEX = DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_POSITIVEX
78 +DDS_CUBEMAP_NEGATIVEX = DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_NEGATIVEX
79 +DDS_CUBEMAP_POSITIVEY = DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_POSITIVEY
80 +DDS_CUBEMAP_NEGATIVEY = DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_NEGATIVEY
81 +DDS_CUBEMAP_POSITIVEZ = DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_POSITIVEZ
82 +DDS_CUBEMAP_NEGATIVEZ = DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_NEGATIVEZ
83 +
84 +
85 +# DXT1
86 +DXT1_FOURCC = 0x31545844
87 +
88 +# DXT3
89 +DXT3_FOURCC = 0x33545844
90 +
91 +# DXT5
92 +DXT5_FOURCC = 0x35545844
93 +
94 +
95 +# dxgiformat.h
96 +
97 +DXGI_FORMAT_BC7_TYPELESS = 97
98 +DXGI_FORMAT_BC7_UNORM = 98
99 +DXGI_FORMAT_BC7_UNORM_SRGB = 99
100 +
101 +
102 +class DdsImageFile(ImageFile.ImageFile):
103 + format = "DDS"
104 + format_description = "DirectDraw Surface"
105 +
106 + def _open(self):
107 + magic, header_size = struct.unpack("<II", self.fp.read(8))
108 + if header_size != 124:
109 + raise IOError("Unsupported header size %r" % (header_size))
110 + header_bytes = self.fp.read(header_size - 4)
111 + if len(header_bytes) != 120:
112 + raise IOError("Incomplete header: %s bytes" % len(header_bytes))
113 + header = BytesIO(header_bytes)
114 +
115 + flags, height, width = struct.unpack("<3I", header.read(12))
116 + self._size = (width, height)
117 + self.mode = "RGBA"
118 +
119 + pitch, depth, mipmaps = struct.unpack("<3I", header.read(12))
120 + struct.unpack("<11I", header.read(44)) # reserved
121 +
122 + # pixel format
123 + pfsize, pfflags = struct.unpack("<2I", header.read(8))
124 + fourcc = header.read(4)
125 + bitcount, = struct.unpack("<I", header.read(4))
126 + masks = struct.unpack("<4I", header.read(16))
127 + if pfflags & 0x40:
128 + # DDPF_RGB - Texture contains uncompressed RGB data
129 + masks = {mask: ["R", "G", "B", "A"][i] for i, mask in enumerate(masks)}
130 + rawmode = ""
131 + if bitcount == 32:
132 + rawmode += masks[0xFF000000]
133 + rawmode += masks[0xFF0000] + masks[0xFF00] + masks[0xFF]
134 +
135 + self.tile = [("raw", (0, 0) + self.size, 0, (rawmode, 0, 1))]
136 + else:
137 + data_start = header_size + 4
138 + n = 0
139 + if fourcc == b"DXT1":
140 + self.pixel_format = "DXT1"
141 + n = 1
142 + elif fourcc == b"DXT3":
143 + self.pixel_format = "DXT3"
144 + n = 2
145 + elif fourcc == b"DXT5":
146 + self.pixel_format = "DXT5"
147 + n = 3
148 + elif fourcc == b"DX10":
149 + data_start += 20
150 + # ignoring flags which pertain to volume textures and cubemaps
151 + dxt10 = BytesIO(self.fp.read(20))
152 + dxgi_format, dimension = struct.unpack("<II", dxt10.read(8))
153 + if dxgi_format in (DXGI_FORMAT_BC7_TYPELESS, DXGI_FORMAT_BC7_UNORM):
154 + self.pixel_format = "BC7"
155 + n = 7
156 + elif dxgi_format == DXGI_FORMAT_BC7_UNORM_SRGB:
157 + self.pixel_format = "BC7"
158 + self.im_info["gamma"] = 1 / 2.2
159 + n = 7
160 + else:
161 + raise NotImplementedError(
162 + "Unimplemented DXGI format %d" % (dxgi_format)
163 + )
164 + else:
165 + raise NotImplementedError("Unimplemented pixel format %r" % (fourcc))
166 +
167 + self.tile = [("bcn", (0, 0) + self.size, data_start, (n))]
168 +
169 + def load_seek(self, pos):
170 + pass
171 +
172 +
173 +def _validate(prefix):
174 + return prefix[:4] == b"DDS "
175 +
176 +
177 +Image.register_open(DdsImageFile.format, DdsImageFile, _validate)
178 +Image.register_extension(DdsImageFile.format, ".dds")
This diff is collapsed. Click to expand it.
1 +#
2 +# The Python Imaging Library.
3 +# $Id$
4 +#
5 +# EXIF tags
6 +#
7 +# Copyright (c) 2003 by Secret Labs AB
8 +#
9 +# See the README file for information on usage and redistribution.
10 +#
11 +
12 +##
13 +# This module provides constants and clear-text names for various
14 +# well-known EXIF tags.
15 +##
16 +
17 +##
18 +# Maps EXIF tags to tag names.
19 +
20 +TAGS = {
21 + # possibly incomplete
22 + 0x000B: "ProcessingSoftware",
23 + 0x00FE: "NewSubfileType",
24 + 0x00FF: "SubfileType",
25 + 0x0100: "ImageWidth",
26 + 0x0101: "ImageLength",
27 + 0x0102: "BitsPerSample",
28 + 0x0103: "Compression",
29 + 0x0106: "PhotometricInterpretation",
30 + 0x0107: "Thresholding",
31 + 0x0108: "CellWidth",
32 + 0x0109: "CellLength",
33 + 0x010A: "FillOrder",
34 + 0x010D: "DocumentName",
35 + 0x010E: "ImageDescription",
36 + 0x010F: "Make",
37 + 0x0110: "Model",
38 + 0x0111: "StripOffsets",
39 + 0x0112: "Orientation",
40 + 0x0115: "SamplesPerPixel",
41 + 0x0116: "RowsPerStrip",
42 + 0x0117: "StripByteCounts",
43 + 0x0118: "MinSampleValue",
44 + 0x0119: "MaxSampleValue",
45 + 0x011A: "XResolution",
46 + 0x011B: "YResolution",
47 + 0x011C: "PlanarConfiguration",
48 + 0x011D: "PageName",
49 + 0x0120: "FreeOffsets",
50 + 0x0121: "FreeByteCounts",
51 + 0x0122: "GrayResponseUnit",
52 + 0x0123: "GrayResponseCurve",
53 + 0x0124: "T4Options",
54 + 0x0125: "T6Options",
55 + 0x0128: "ResolutionUnit",
56 + 0x0129: "PageNumber",
57 + 0x012D: "TransferFunction",
58 + 0x0131: "Software",
59 + 0x0132: "DateTime",
60 + 0x013B: "Artist",
61 + 0x013C: "HostComputer",
62 + 0x013D: "Predictor",
63 + 0x013E: "WhitePoint",
64 + 0x013F: "PrimaryChromaticities",
65 + 0x0140: "ColorMap",
66 + 0x0141: "HalftoneHints",
67 + 0x0142: "TileWidth",
68 + 0x0143: "TileLength",
69 + 0x0144: "TileOffsets",
70 + 0x0145: "TileByteCounts",
71 + 0x014A: "SubIFDs",
72 + 0x014C: "InkSet",
73 + 0x014D: "InkNames",
74 + 0x014E: "NumberOfInks",
75 + 0x0150: "DotRange",
76 + 0x0151: "TargetPrinter",
77 + 0x0152: "ExtraSamples",
78 + 0x0153: "SampleFormat",
79 + 0x0154: "SMinSampleValue",
80 + 0x0155: "SMaxSampleValue",
81 + 0x0156: "TransferRange",
82 + 0x0157: "ClipPath",
83 + 0x0158: "XClipPathUnits",
84 + 0x0159: "YClipPathUnits",
85 + 0x015A: "Indexed",
86 + 0x015B: "JPEGTables",
87 + 0x015F: "OPIProxy",
88 + 0x0200: "JPEGProc",
89 + 0x0201: "JpegIFOffset",
90 + 0x0202: "JpegIFByteCount",
91 + 0x0203: "JpegRestartInterval",
92 + 0x0205: "JpegLosslessPredictors",
93 + 0x0206: "JpegPointTransforms",
94 + 0x0207: "JpegQTables",
95 + 0x0208: "JpegDCTables",
96 + 0x0209: "JpegACTables",
97 + 0x0211: "YCbCrCoefficients",
98 + 0x0212: "YCbCrSubSampling",
99 + 0x0213: "YCbCrPositioning",
100 + 0x0214: "ReferenceBlackWhite",
101 + 0x02BC: "XMLPacket",
102 + 0x1000: "RelatedImageFileFormat",
103 + 0x1001: "RelatedImageWidth",
104 + 0x1002: "RelatedImageLength",
105 + 0x4746: "Rating",
106 + 0x4749: "RatingPercent",
107 + 0x800D: "ImageID",
108 + 0x828D: "CFARepeatPatternDim",
109 + 0x828E: "CFAPattern",
110 + 0x828F: "BatteryLevel",
111 + 0x8298: "Copyright",
112 + 0x829A: "ExposureTime",
113 + 0x829D: "FNumber",
114 + 0x83BB: "IPTCNAA",
115 + 0x8649: "ImageResources",
116 + 0x8769: "ExifOffset",
117 + 0x8773: "InterColorProfile",
118 + 0x8822: "ExposureProgram",
119 + 0x8824: "SpectralSensitivity",
120 + 0x8825: "GPSInfo",
121 + 0x8827: "ISOSpeedRatings",
122 + 0x8828: "OECF",
123 + 0x8829: "Interlace",
124 + 0x882A: "TimeZoneOffset",
125 + 0x882B: "SelfTimerMode",
126 + 0x9000: "ExifVersion",
127 + 0x9003: "DateTimeOriginal",
128 + 0x9004: "DateTimeDigitized",
129 + 0x9101: "ComponentsConfiguration",
130 + 0x9102: "CompressedBitsPerPixel",
131 + 0x9201: "ShutterSpeedValue",
132 + 0x9202: "ApertureValue",
133 + 0x9203: "BrightnessValue",
134 + 0x9204: "ExposureBiasValue",
135 + 0x9205: "MaxApertureValue",
136 + 0x9206: "SubjectDistance",
137 + 0x9207: "MeteringMode",
138 + 0x9208: "LightSource",
139 + 0x9209: "Flash",
140 + 0x920A: "FocalLength",
141 + 0x920B: "FlashEnergy",
142 + 0x920C: "SpatialFrequencyResponse",
143 + 0x920D: "Noise",
144 + 0x9211: "ImageNumber",
145 + 0x9212: "SecurityClassification",
146 + 0x9213: "ImageHistory",
147 + 0x9214: "SubjectLocation",
148 + 0x9215: "ExposureIndex",
149 + 0x9216: "TIFF/EPStandardID",
150 + 0x927C: "MakerNote",
151 + 0x9286: "UserComment",
152 + 0x9290: "SubsecTime",
153 + 0x9291: "SubsecTimeOriginal",
154 + 0x9292: "SubsecTimeDigitized",
155 + 0x9C9B: "XPTitle",
156 + 0x9C9C: "XPComment",
157 + 0x9C9D: "XPAuthor",
158 + 0x9C9E: "XPKeywords",
159 + 0x9C9F: "XPSubject",
160 + 0xA000: "FlashPixVersion",
161 + 0xA001: "ColorSpace",
162 + 0xA002: "ExifImageWidth",
163 + 0xA003: "ExifImageHeight",
164 + 0xA004: "RelatedSoundFile",
165 + 0xA005: "ExifInteroperabilityOffset",
166 + 0xA20B: "FlashEnergy",
167 + 0xA20C: "SpatialFrequencyResponse",
168 + 0xA20E: "FocalPlaneXResolution",
169 + 0xA20F: "FocalPlaneYResolution",
170 + 0xA210: "FocalPlaneResolutionUnit",
171 + 0xA214: "SubjectLocation",
172 + 0xA215: "ExposureIndex",
173 + 0xA217: "SensingMethod",
174 + 0xA300: "FileSource",
175 + 0xA301: "SceneType",
176 + 0xA302: "CFAPattern",
177 + 0xA401: "CustomRendered",
178 + 0xA402: "ExposureMode",
179 + 0xA403: "WhiteBalance",
180 + 0xA404: "DigitalZoomRatio",
181 + 0xA405: "FocalLengthIn35mmFilm",
182 + 0xA406: "SceneCaptureType",
183 + 0xA407: "GainControl",
184 + 0xA408: "Contrast",
185 + 0xA409: "Saturation",
186 + 0xA40A: "Sharpness",
187 + 0xA40B: "DeviceSettingDescription",
188 + 0xA40C: "SubjectDistanceRange",
189 + 0xA420: "ImageUniqueID",
190 + 0xA430: "CameraOwnerName",
191 + 0xA431: "BodySerialNumber",
192 + 0xA432: "LensSpecification",
193 + 0xA433: "LensMake",
194 + 0xA434: "LensModel",
195 + 0xA435: "LensSerialNumber",
196 + 0xA500: "Gamma",
197 + 0xC4A5: "PrintImageMatching",
198 + 0xC612: "DNGVersion",
199 + 0xC613: "DNGBackwardVersion",
200 + 0xC614: "UniqueCameraModel",
201 + 0xC615: "LocalizedCameraModel",
202 + 0xC616: "CFAPlaneColor",
203 + 0xC617: "CFALayout",
204 + 0xC618: "LinearizationTable",
205 + 0xC619: "BlackLevelRepeatDim",
206 + 0xC61A: "BlackLevel",
207 + 0xC61B: "BlackLevelDeltaH",
208 + 0xC61C: "BlackLevelDeltaV",
209 + 0xC61D: "WhiteLevel",
210 + 0xC61E: "DefaultScale",
211 + 0xC61F: "DefaultCropOrigin",
212 + 0xC620: "DefaultCropSize",
213 + 0xC621: "ColorMatrix1",
214 + 0xC622: "ColorMatrix2",
215 + 0xC623: "CameraCalibration1",
216 + 0xC624: "CameraCalibration2",
217 + 0xC625: "ReductionMatrix1",
218 + 0xC626: "ReductionMatrix2",
219 + 0xC627: "AnalogBalance",
220 + 0xC628: "AsShotNeutral",
221 + 0xC629: "AsShotWhiteXY",
222 + 0xC62A: "BaselineExposure",
223 + 0xC62B: "BaselineNoise",
224 + 0xC62C: "BaselineSharpness",
225 + 0xC62D: "BayerGreenSplit",
226 + 0xC62E: "LinearResponseLimit",
227 + 0xC62F: "CameraSerialNumber",
228 + 0xC630: "LensInfo",
229 + 0xC631: "ChromaBlurRadius",
230 + 0xC632: "AntiAliasStrength",
231 + 0xC633: "ShadowScale",
232 + 0xC634: "DNGPrivateData",
233 + 0xC635: "MakerNoteSafety",
234 + 0xC65A: "CalibrationIlluminant1",
235 + 0xC65B: "CalibrationIlluminant2",
236 + 0xC65C: "BestQualityScale",
237 + 0xC65D: "RawDataUniqueID",
238 + 0xC68B: "OriginalRawFileName",
239 + 0xC68C: "OriginalRawFileData",
240 + 0xC68D: "ActiveArea",
241 + 0xC68E: "MaskedAreas",
242 + 0xC68F: "AsShotICCProfile",
243 + 0xC690: "AsShotPreProfileMatrix",
244 + 0xC691: "CurrentICCProfile",
245 + 0xC692: "CurrentPreProfileMatrix",
246 + 0xC6BF: "ColorimetricReference",
247 + 0xC6F3: "CameraCalibrationSignature",
248 + 0xC6F4: "ProfileCalibrationSignature",
249 + 0xC6F6: "AsShotProfileName",
250 + 0xC6F7: "NoiseReductionApplied",
251 + 0xC6F8: "ProfileName",
252 + 0xC6F9: "ProfileHueSatMapDims",
253 + 0xC6FA: "ProfileHueSatMapData1",
254 + 0xC6FB: "ProfileHueSatMapData2",
255 + 0xC6FC: "ProfileToneCurve",
256 + 0xC6FD: "ProfileEmbedPolicy",
257 + 0xC6FE: "ProfileCopyright",
258 + 0xC714: "ForwardMatrix1",
259 + 0xC715: "ForwardMatrix2",
260 + 0xC716: "PreviewApplicationName",
261 + 0xC717: "PreviewApplicationVersion",
262 + 0xC718: "PreviewSettingsName",
263 + 0xC719: "PreviewSettingsDigest",
264 + 0xC71A: "PreviewColorSpace",
265 + 0xC71B: "PreviewDateTime",
266 + 0xC71C: "RawImageDigest",
267 + 0xC71D: "OriginalRawFileDigest",
268 + 0xC71E: "SubTileBlockSize",
269 + 0xC71F: "RowInterleaveFactor",
270 + 0xC725: "ProfileLookTableDims",
271 + 0xC726: "ProfileLookTableData",
272 + 0xC740: "OpcodeList1",
273 + 0xC741: "OpcodeList2",
274 + 0xC74E: "OpcodeList3",
275 + 0xC761: "NoiseProfile",
276 +}
277 +
278 +##
279 +# Maps EXIF GPS tags to tag names.
280 +
281 +GPSTAGS = {
282 + 0: "GPSVersionID",
283 + 1: "GPSLatitudeRef",
284 + 2: "GPSLatitude",
285 + 3: "GPSLongitudeRef",
286 + 4: "GPSLongitude",
287 + 5: "GPSAltitudeRef",
288 + 6: "GPSAltitude",
289 + 7: "GPSTimeStamp",
290 + 8: "GPSSatellites",
291 + 9: "GPSStatus",
292 + 10: "GPSMeasureMode",
293 + 11: "GPSDOP",
294 + 12: "GPSSpeedRef",
295 + 13: "GPSSpeed",
296 + 14: "GPSTrackRef",
297 + 15: "GPSTrack",
298 + 16: "GPSImgDirectionRef",
299 + 17: "GPSImgDirection",
300 + 18: "GPSMapDatum",
301 + 19: "GPSDestLatitudeRef",
302 + 20: "GPSDestLatitude",
303 + 21: "GPSDestLongitudeRef",
304 + 22: "GPSDestLongitude",
305 + 23: "GPSDestBearingRef",
306 + 24: "GPSDestBearing",
307 + 25: "GPSDestDistanceRef",
308 + 26: "GPSDestDistance",
309 + 27: "GPSProcessingMethod",
310 + 28: "GPSAreaInformation",
311 + 29: "GPSDateStamp",
312 + 30: "GPSDifferential",
313 + 31: "GPSHPositioningError",
314 +}
1 +#
2 +# The Python Imaging Library
3 +# $Id$
4 +#
5 +# FITS stub adapter
6 +#
7 +# Copyright (c) 1998-2003 by Fredrik Lundh
8 +#
9 +# See the README file for information on usage and redistribution.
10 +#
11 +
12 +from . import Image, ImageFile
13 +
14 +_handler = None
15 +
16 +
17 +def register_handler(handler):
18 + """
19 + Install application-specific FITS image handler.
20 +
21 + :param handler: Handler object.
22 + """
23 + global _handler
24 + _handler = handler
25 +
26 +
27 +# --------------------------------------------------------------------
28 +# Image adapter
29 +
30 +
31 +def _accept(prefix):
32 + return prefix[:6] == b"SIMPLE"
33 +
34 +
35 +class FITSStubImageFile(ImageFile.StubImageFile):
36 +
37 + format = "FITS"
38 + format_description = "FITS"
39 +
40 + def _open(self):
41 +
42 + offset = self.fp.tell()
43 +
44 + if not _accept(self.fp.read(6)):
45 + raise SyntaxError("Not a FITS file")
46 +
47 + # FIXME: add more sanity checks here; mandatory header items
48 + # include SIMPLE, BITPIX, NAXIS, etc.
49 +
50 + self.fp.seek(offset)
51 +
52 + # make something up
53 + self.mode = "F"
54 + self._size = 1, 1
55 +
56 + loader = self._load()
57 + if loader:
58 + loader.open(self)
59 +
60 + def _load(self):
61 + return _handler
62 +
63 +
64 +def _save(im, fp, filename):
65 + if _handler is None or not hasattr("_handler", "save"):
66 + raise IOError("FITS save handler not installed")
67 + _handler.save(im, fp, filename)
68 +
69 +
70 +# --------------------------------------------------------------------
71 +# Registry
72 +
73 +Image.register_open(FITSStubImageFile.format, FITSStubImageFile, _accept)
74 +Image.register_save(FITSStubImageFile.format, _save)
75 +
76 +Image.register_extensions(FITSStubImageFile.format, [".fit", ".fits"])
1 +#
2 +# The Python Imaging Library.
3 +# $Id$
4 +#
5 +# FLI/FLC file handling.
6 +#
7 +# History:
8 +# 95-09-01 fl Created
9 +# 97-01-03 fl Fixed parser, setup decoder tile
10 +# 98-07-15 fl Renamed offset attribute to avoid name clash
11 +#
12 +# Copyright (c) Secret Labs AB 1997-98.
13 +# Copyright (c) Fredrik Lundh 1995-97.
14 +#
15 +# See the README file for information on usage and redistribution.
16 +#
17 +
18 +
19 +from . import Image, ImageFile, ImagePalette
20 +from ._binary import i8, i16le as i16, i32le as i32, o8
21 +
22 +# __version__ is deprecated and will be removed in a future version. Use
23 +# PIL.__version__ instead.
24 +__version__ = "0.2"
25 +
26 +
27 +#
28 +# decoder
29 +
30 +
31 +def _accept(prefix):
32 + return len(prefix) >= 6 and i16(prefix[4:6]) in [0xAF11, 0xAF12]
33 +
34 +
35 +##
36 +# Image plugin for the FLI/FLC animation format. Use the <b>seek</b>
37 +# method to load individual frames.
38 +
39 +
40 +class FliImageFile(ImageFile.ImageFile):
41 +
42 + format = "FLI"
43 + format_description = "Autodesk FLI/FLC Animation"
44 + _close_exclusive_fp_after_loading = False
45 +
46 + def _open(self):
47 +
48 + # HEAD
49 + s = self.fp.read(128)
50 + magic = i16(s[4:6])
51 + if not (
52 + magic in [0xAF11, 0xAF12]
53 + and i16(s[14:16]) in [0, 3] # flags
54 + and s[20:22] == b"\x00\x00" # reserved
55 + ):
56 + raise SyntaxError("not an FLI/FLC file")
57 +
58 + # frames
59 + self.__framecount = i16(s[6:8])
60 +
61 + # image characteristics
62 + self.mode = "P"
63 + self._size = i16(s[8:10]), i16(s[10:12])
64 +
65 + # animation speed
66 + duration = i32(s[16:20])
67 + if magic == 0xAF11:
68 + duration = (duration * 1000) // 70
69 + self.info["duration"] = duration
70 +
71 + # look for palette
72 + palette = [(a, a, a) for a in range(256)]
73 +
74 + s = self.fp.read(16)
75 +
76 + self.__offset = 128
77 +
78 + if i16(s[4:6]) == 0xF100:
79 + # prefix chunk; ignore it
80 + self.__offset = self.__offset + i32(s)
81 + s = self.fp.read(16)
82 +
83 + if i16(s[4:6]) == 0xF1FA:
84 + # look for palette chunk
85 + s = self.fp.read(6)
86 + if i16(s[4:6]) == 11:
87 + self._palette(palette, 2)
88 + elif i16(s[4:6]) == 4:
89 + self._palette(palette, 0)
90 +
91 + palette = [o8(r) + o8(g) + o8(b) for (r, g, b) in palette]
92 + self.palette = ImagePalette.raw("RGB", b"".join(palette))
93 +
94 + # set things up to decode first frame
95 + self.__frame = -1
96 + self.__fp = self.fp
97 + self.__rewind = self.fp.tell()
98 + self.seek(0)
99 +
100 + def _palette(self, palette, shift):
101 + # load palette
102 +
103 + i = 0
104 + for e in range(i16(self.fp.read(2))):
105 + s = self.fp.read(2)
106 + i = i + i8(s[0])
107 + n = i8(s[1])
108 + if n == 0:
109 + n = 256
110 + s = self.fp.read(n * 3)
111 + for n in range(0, len(s), 3):
112 + r = i8(s[n]) << shift
113 + g = i8(s[n + 1]) << shift
114 + b = i8(s[n + 2]) << shift
115 + palette[i] = (r, g, b)
116 + i += 1
117 +
118 + @property
119 + def n_frames(self):
120 + return self.__framecount
121 +
122 + @property
123 + def is_animated(self):
124 + return self.__framecount > 1
125 +
126 + def seek(self, frame):
127 + if not self._seek_check(frame):
128 + return
129 + if frame < self.__frame:
130 + self._seek(0)
131 +
132 + for f in range(self.__frame + 1, frame + 1):
133 + self._seek(f)
134 +
135 + def _seek(self, frame):
136 + if frame == 0:
137 + self.__frame = -1
138 + self.__fp.seek(self.__rewind)
139 + self.__offset = 128
140 + else:
141 + # ensure that the previous frame was loaded
142 + self.load()
143 +
144 + if frame != self.__frame + 1:
145 + raise ValueError("cannot seek to frame %d" % frame)
146 + self.__frame = frame
147 +
148 + # move to next frame
149 + self.fp = self.__fp
150 + self.fp.seek(self.__offset)
151 +
152 + s = self.fp.read(4)
153 + if not s:
154 + raise EOFError
155 +
156 + framesize = i32(s)
157 +
158 + self.decodermaxblock = framesize
159 + self.tile = [("fli", (0, 0) + self.size, self.__offset, None)]
160 +
161 + self.__offset += framesize
162 +
163 + def tell(self):
164 + return self.__frame
165 +
166 + def _close__fp(self):
167 + try:
168 + if self.__fp != self.fp:
169 + self.__fp.close()
170 + except AttributeError:
171 + pass
172 + finally:
173 + self.__fp = None
174 +
175 +
176 +#
177 +# registry
178 +
179 +Image.register_open(FliImageFile.format, FliImageFile, _accept)
180 +
181 +Image.register_extensions(FliImageFile.format, [".fli", ".flc"])
1 +#
2 +# The Python Imaging Library
3 +# $Id$
4 +#
5 +# base class for raster font file parsers
6 +#
7 +# history:
8 +# 1997-06-05 fl created
9 +# 1997-08-19 fl restrict image width
10 +#
11 +# Copyright (c) 1997-1998 by Secret Labs AB
12 +# Copyright (c) 1997-1998 by Fredrik Lundh
13 +#
14 +# See the README file for information on usage and redistribution.
15 +#
16 +
17 +from __future__ import print_function
18 +
19 +import os
20 +
21 +from . import Image, _binary
22 +
23 +WIDTH = 800
24 +
25 +
26 +def puti16(fp, values):
27 + # write network order (big-endian) 16-bit sequence
28 + for v in values:
29 + if v < 0:
30 + v += 65536
31 + fp.write(_binary.o16be(v))
32 +
33 +
34 +##
35 +# Base class for raster font file handlers.
36 +
37 +
38 +class FontFile(object):
39 +
40 + bitmap = None
41 +
42 + def __init__(self):
43 +
44 + self.info = {}
45 + self.glyph = [None] * 256
46 +
47 + def __getitem__(self, ix):
48 + return self.glyph[ix]
49 +
50 + def compile(self):
51 + """Create metrics and bitmap"""
52 +
53 + if self.bitmap:
54 + return
55 +
56 + # create bitmap large enough to hold all data
57 + h = w = maxwidth = 0
58 + lines = 1
59 + for glyph in self:
60 + if glyph:
61 + d, dst, src, im = glyph
62 + h = max(h, src[3] - src[1])
63 + w = w + (src[2] - src[0])
64 + if w > WIDTH:
65 + lines += 1
66 + w = src[2] - src[0]
67 + maxwidth = max(maxwidth, w)
68 +
69 + xsize = maxwidth
70 + ysize = lines * h
71 +
72 + if xsize == 0 and ysize == 0:
73 + return ""
74 +
75 + self.ysize = h
76 +
77 + # paste glyphs into bitmap
78 + self.bitmap = Image.new("1", (xsize, ysize))
79 + self.metrics = [None] * 256
80 + x = y = 0
81 + for i in range(256):
82 + glyph = self[i]
83 + if glyph:
84 + d, dst, src, im = glyph
85 + xx = src[2] - src[0]
86 + # yy = src[3] - src[1]
87 + x0, y0 = x, y
88 + x = x + xx
89 + if x > WIDTH:
90 + x, y = 0, y + h
91 + x0, y0 = x, y
92 + x = xx
93 + s = src[0] + x0, src[1] + y0, src[2] + x0, src[3] + y0
94 + self.bitmap.paste(im.crop(src), s)
95 + self.metrics[i] = d, dst, s
96 +
97 + def save(self, filename):
98 + """Save font"""
99 +
100 + self.compile()
101 +
102 + # font data
103 + self.bitmap.save(os.path.splitext(filename)[0] + ".pbm", "PNG")
104 +
105 + # font metrics
106 + with open(os.path.splitext(filename)[0] + ".pil", "wb") as fp:
107 + fp.write(b"PILfont\n")
108 + fp.write((";;;;;;%d;\n" % self.ysize).encode("ascii")) # HACK!!!
109 + fp.write(b"DATA\n")
110 + for id in range(256):
111 + m = self.metrics[id]
112 + if not m:
113 + puti16(fp, [0] * 10)
114 + else:
115 + puti16(fp, m[0] + m[1] + m[2])
1 +#
2 +# THIS IS WORK IN PROGRESS
3 +#
4 +# The Python Imaging Library.
5 +# $Id$
6 +#
7 +# FlashPix support for PIL
8 +#
9 +# History:
10 +# 97-01-25 fl Created (reads uncompressed RGB images only)
11 +#
12 +# Copyright (c) Secret Labs AB 1997.
13 +# Copyright (c) Fredrik Lundh 1997.
14 +#
15 +# See the README file for information on usage and redistribution.
16 +#
17 +
18 +from __future__ import print_function
19 +
20 +import olefile
21 +
22 +from . import Image, ImageFile
23 +from ._binary import i8, i32le as i32
24 +
25 +# __version__ is deprecated and will be removed in a future version. Use
26 +# PIL.__version__ instead.
27 +__version__ = "0.1"
28 +
29 +# we map from colour field tuples to (mode, rawmode) descriptors
30 +MODES = {
31 + # opacity
32 + (0x00007FFE): ("A", "L"),
33 + # monochrome
34 + (0x00010000,): ("L", "L"),
35 + (0x00018000, 0x00017FFE): ("RGBA", "LA"),
36 + # photo YCC
37 + (0x00020000, 0x00020001, 0x00020002): ("RGB", "YCC;P"),
38 + (0x00028000, 0x00028001, 0x00028002, 0x00027FFE): ("RGBA", "YCCA;P"),
39 + # standard RGB (NIFRGB)
40 + (0x00030000, 0x00030001, 0x00030002): ("RGB", "RGB"),
41 + (0x00038000, 0x00038001, 0x00038002, 0x00037FFE): ("RGBA", "RGBA"),
42 +}
43 +
44 +
45 +#
46 +# --------------------------------------------------------------------
47 +
48 +
49 +def _accept(prefix):
50 + return prefix[:8] == olefile.MAGIC
51 +
52 +
53 +##
54 +# Image plugin for the FlashPix images.
55 +
56 +
57 +class FpxImageFile(ImageFile.ImageFile):
58 +
59 + format = "FPX"
60 + format_description = "FlashPix"
61 +
62 + def _open(self):
63 + #
64 + # read the OLE directory and see if this is a likely
65 + # to be a FlashPix file
66 +
67 + try:
68 + self.ole = olefile.OleFileIO(self.fp)
69 + except IOError:
70 + raise SyntaxError("not an FPX file; invalid OLE file")
71 +
72 + if self.ole.root.clsid != "56616700-C154-11CE-8553-00AA00A1F95B":
73 + raise SyntaxError("not an FPX file; bad root CLSID")
74 +
75 + self._open_index(1)
76 +
77 + def _open_index(self, index=1):
78 + #
79 + # get the Image Contents Property Set
80 +
81 + prop = self.ole.getproperties(
82 + ["Data Object Store %06d" % index, "\005Image Contents"]
83 + )
84 +
85 + # size (highest resolution)
86 +
87 + self._size = prop[0x1000002], prop[0x1000003]
88 +
89 + size = max(self.size)
90 + i = 1
91 + while size > 64:
92 + size = size / 2
93 + i += 1
94 + self.maxid = i - 1
95 +
96 + # mode. instead of using a single field for this, flashpix
97 + # requires you to specify the mode for each channel in each
98 + # resolution subimage, and leaves it to the decoder to make
99 + # sure that they all match. for now, we'll cheat and assume
100 + # that this is always the case.
101 +
102 + id = self.maxid << 16
103 +
104 + s = prop[0x2000002 | id]
105 +
106 + colors = []
107 + for i in range(i32(s, 4)):
108 + # note: for now, we ignore the "uncalibrated" flag
109 + colors.append(i32(s, 8 + i * 4) & 0x7FFFFFFF)
110 +
111 + self.mode, self.rawmode = MODES[tuple(colors)]
112 +
113 + # load JPEG tables, if any
114 + self.jpeg = {}
115 + for i in range(256):
116 + id = 0x3000001 | (i << 16)
117 + if id in prop:
118 + self.jpeg[i] = prop[id]
119 +
120 + self._open_subimage(1, self.maxid)
121 +
122 + def _open_subimage(self, index=1, subimage=0):
123 + #
124 + # setup tile descriptors for a given subimage
125 +
126 + stream = [
127 + "Data Object Store %06d" % index,
128 + "Resolution %04d" % subimage,
129 + "Subimage 0000 Header",
130 + ]
131 +
132 + fp = self.ole.openstream(stream)
133 +
134 + # skip prefix
135 + fp.read(28)
136 +
137 + # header stream
138 + s = fp.read(36)
139 +
140 + size = i32(s, 4), i32(s, 8)
141 + # tilecount = i32(s, 12)
142 + tilesize = i32(s, 16), i32(s, 20)
143 + # channels = i32(s, 24)
144 + offset = i32(s, 28)
145 + length = i32(s, 32)
146 +
147 + if size != self.size:
148 + raise IOError("subimage mismatch")
149 +
150 + # get tile descriptors
151 + fp.seek(28 + offset)
152 + s = fp.read(i32(s, 12) * length)
153 +
154 + x = y = 0
155 + xsize, ysize = size
156 + xtile, ytile = tilesize
157 + self.tile = []
158 +
159 + for i in range(0, len(s), length):
160 +
161 + compression = i32(s, i + 8)
162 +
163 + if compression == 0:
164 + self.tile.append(
165 + (
166 + "raw",
167 + (x, y, x + xtile, y + ytile),
168 + i32(s, i) + 28,
169 + (self.rawmode),
170 + )
171 + )
172 +
173 + elif compression == 1:
174 +
175 + # FIXME: the fill decoder is not implemented
176 + self.tile.append(
177 + (
178 + "fill",
179 + (x, y, x + xtile, y + ytile),
180 + i32(s, i) + 28,
181 + (self.rawmode, s[12:16]),
182 + )
183 + )
184 +
185 + elif compression == 2:
186 +
187 + internal_color_conversion = i8(s[14])
188 + jpeg_tables = i8(s[15])
189 + rawmode = self.rawmode
190 +
191 + if internal_color_conversion:
192 + # The image is stored as usual (usually YCbCr).
193 + if rawmode == "RGBA":
194 + # For "RGBA", data is stored as YCbCrA based on
195 + # negative RGB. The following trick works around
196 + # this problem :
197 + jpegmode, rawmode = "YCbCrK", "CMYK"
198 + else:
199 + jpegmode = None # let the decoder decide
200 +
201 + else:
202 + # The image is stored as defined by rawmode
203 + jpegmode = rawmode
204 +
205 + self.tile.append(
206 + (
207 + "jpeg",
208 + (x, y, x + xtile, y + ytile),
209 + i32(s, i) + 28,
210 + (rawmode, jpegmode),
211 + )
212 + )
213 +
214 + # FIXME: jpeg tables are tile dependent; the prefix
215 + # data must be placed in the tile descriptor itself!
216 +
217 + if jpeg_tables:
218 + self.tile_prefix = self.jpeg[jpeg_tables]
219 +
220 + else:
221 + raise IOError("unknown/invalid compression")
222 +
223 + x = x + xtile
224 + if x >= xsize:
225 + x, y = 0, y + ytile
226 + if y >= ysize:
227 + break # isn't really required
228 +
229 + self.stream = stream
230 + self.fp = None
231 +
232 + def load(self):
233 +
234 + if not self.fp:
235 + self.fp = self.ole.openstream(self.stream[:2] + ["Subimage 0000 Data"])
236 +
237 + return ImageFile.ImageFile.load(self)
238 +
239 +
240 +#
241 +# --------------------------------------------------------------------
242 +
243 +
244 +Image.register_open(FpxImageFile.format, FpxImageFile, _accept)
245 +
246 +Image.register_extension(FpxImageFile.format, ".fpx")
1 +"""
2 +A Pillow loader for .ftc and .ftu files (FTEX)
3 +Jerome Leclanche <jerome@leclan.ch>
4 +
5 +The contents of this file are hereby released in the public domain (CC0)
6 +Full text of the CC0 license:
7 + https://creativecommons.org/publicdomain/zero/1.0/
8 +
9 +Independence War 2: Edge Of Chaos - Texture File Format - 16 October 2001
10 +
11 +The textures used for 3D objects in Independence War 2: Edge Of Chaos are in a
12 +packed custom format called FTEX. This file format uses file extensions FTC
13 +and FTU.
14 +* FTC files are compressed textures (using standard texture compression).
15 +* FTU files are not compressed.
16 +Texture File Format
17 +The FTC and FTU texture files both use the same format. This
18 +has the following structure:
19 +{header}
20 +{format_directory}
21 +{data}
22 +Where:
23 +{header} = {
24 + u32:magic,
25 + u32:version,
26 + u32:width,
27 + u32:height,
28 + u32:mipmap_count,
29 + u32:format_count
30 +}
31 +
32 +* The "magic" number is "FTEX".
33 +* "width" and "height" are the dimensions of the texture.
34 +* "mipmap_count" is the number of mipmaps in the texture.
35 +* "format_count" is the number of texture formats (different versions of the
36 +same texture) in this file.
37 +
38 +{format_directory} = format_count * { u32:format, u32:where }
39 +
40 +The format value is 0 for DXT1 compressed textures and 1 for 24-bit RGB
41 +uncompressed textures.
42 +The texture data for a format starts at the position "where" in the file.
43 +
44 +Each set of texture data in the file has the following structure:
45 +{data} = format_count * { u32:mipmap_size, mipmap_size * { u8 } }
46 +* "mipmap_size" is the number of bytes in that mip level. For compressed
47 +textures this is the size of the texture data compressed with DXT1. For 24 bit
48 +uncompressed textures, this is 3 * width * height. Following this are the image
49 +bytes for that mipmap level.
50 +
51 +Note: All data is stored in little-Endian (Intel) byte order.
52 +"""
53 +
54 +import struct
55 +from io import BytesIO
56 +
57 +from . import Image, ImageFile
58 +
59 +MAGIC = b"FTEX"
60 +FORMAT_DXT1 = 0
61 +FORMAT_UNCOMPRESSED = 1
62 +
63 +
64 +class FtexImageFile(ImageFile.ImageFile):
65 + format = "FTEX"
66 + format_description = "Texture File Format (IW2:EOC)"
67 +
68 + def _open(self):
69 + struct.unpack("<I", self.fp.read(4)) # magic
70 + struct.unpack("<i", self.fp.read(4)) # version
71 + self._size = struct.unpack("<2i", self.fp.read(8))
72 + mipmap_count, format_count = struct.unpack("<2i", self.fp.read(8))
73 +
74 + self.mode = "RGB"
75 +
76 + # Only support single-format files.
77 + # I don't know of any multi-format file.
78 + assert format_count == 1
79 +
80 + format, where = struct.unpack("<2i", self.fp.read(8))
81 + self.fp.seek(where)
82 + mipmap_size, = struct.unpack("<i", self.fp.read(4))
83 +
84 + data = self.fp.read(mipmap_size)
85 +
86 + if format == FORMAT_DXT1:
87 + self.mode = "RGBA"
88 + self.tile = [("bcn", (0, 0) + self.size, 0, (1))]
89 + elif format == FORMAT_UNCOMPRESSED:
90 + self.tile = [("raw", (0, 0) + self.size, 0, ("RGB", 0, 1))]
91 + else:
92 + raise ValueError("Invalid texture compression format: %r" % (format))
93 +
94 + self.fp.close()
95 + self.fp = BytesIO(data)
96 +
97 + def load_seek(self, pos):
98 + pass
99 +
100 +
101 +def _validate(prefix):
102 + return prefix[:4] == MAGIC
103 +
104 +
105 +Image.register_open(FtexImageFile.format, FtexImageFile, _validate)
106 +Image.register_extensions(FtexImageFile.format, [".ftc", ".ftu"])
1 +#
2 +# The Python Imaging Library
3 +#
4 +# load a GIMP brush file
5 +#
6 +# History:
7 +# 96-03-14 fl Created
8 +# 16-01-08 es Version 2
9 +#
10 +# Copyright (c) Secret Labs AB 1997.
11 +# Copyright (c) Fredrik Lundh 1996.
12 +# Copyright (c) Eric Soroos 2016.
13 +#
14 +# See the README file for information on usage and redistribution.
15 +#
16 +#
17 +# See https://github.com/GNOME/gimp/blob/master/devel-docs/gbr.txt for
18 +# format documentation.
19 +#
20 +# This code Interprets version 1 and 2 .gbr files.
21 +# Version 1 files are obsolete, and should not be used for new
22 +# brushes.
23 +# Version 2 files are saved by GIMP v2.8 (at least)
24 +# Version 3 files have a format specifier of 18 for 16bit floats in
25 +# the color depth field. This is currently unsupported by Pillow.
26 +
27 +from . import Image, ImageFile
28 +from ._binary import i32be as i32
29 +
30 +
31 +def _accept(prefix):
32 + return len(prefix) >= 8 and i32(prefix[:4]) >= 20 and i32(prefix[4:8]) in (1, 2)
33 +
34 +
35 +##
36 +# Image plugin for the GIMP brush format.
37 +
38 +
39 +class GbrImageFile(ImageFile.ImageFile):
40 +
41 + format = "GBR"
42 + format_description = "GIMP brush file"
43 +
44 + def _open(self):
45 + header_size = i32(self.fp.read(4))
46 + version = i32(self.fp.read(4))
47 + if header_size < 20:
48 + raise SyntaxError("not a GIMP brush")
49 + if version not in (1, 2):
50 + raise SyntaxError("Unsupported GIMP brush version: %s" % version)
51 +
52 + width = i32(self.fp.read(4))
53 + height = i32(self.fp.read(4))
54 + color_depth = i32(self.fp.read(4))
55 + if width <= 0 or height <= 0:
56 + raise SyntaxError("not a GIMP brush")
57 + if color_depth not in (1, 4):
58 + raise SyntaxError("Unsupported GIMP brush color depth: %s" % color_depth)
59 +
60 + if version == 1:
61 + comment_length = header_size - 20
62 + else:
63 + comment_length = header_size - 28
64 + magic_number = self.fp.read(4)
65 + if magic_number != b"GIMP":
66 + raise SyntaxError("not a GIMP brush, bad magic number")
67 + self.info["spacing"] = i32(self.fp.read(4))
68 +
69 + comment = self.fp.read(comment_length)[:-1]
70 +
71 + if color_depth == 1:
72 + self.mode = "L"
73 + else:
74 + self.mode = "RGBA"
75 +
76 + self._size = width, height
77 +
78 + self.info["comment"] = comment
79 +
80 + # Image might not be small
81 + Image._decompression_bomb_check(self.size)
82 +
83 + # Data is an uncompressed block of w * h * bytes/pixel
84 + self._data_size = width * height * color_depth
85 +
86 + def load(self):
87 + self.im = Image.core.new(self.mode, self.size)
88 + self.frombytes(self.fp.read(self._data_size))
89 +
90 +
91 +#
92 +# registry
93 +
94 +
95 +Image.register_open(GbrImageFile.format, GbrImageFile, _accept)
96 +Image.register_extension(GbrImageFile.format, ".gbr")
1 +#
2 +# The Python Imaging Library.
3 +# $Id$
4 +#
5 +# GD file handling
6 +#
7 +# History:
8 +# 1996-04-12 fl Created
9 +#
10 +# Copyright (c) 1997 by Secret Labs AB.
11 +# Copyright (c) 1996 by Fredrik Lundh.
12 +#
13 +# See the README file for information on usage and redistribution.
14 +#
15 +
16 +
17 +# NOTE: This format cannot be automatically recognized, so the
18 +# class is not registered for use with Image.open(). To open a
19 +# gd file, use the GdImageFile.open() function instead.
20 +
21 +# THE GD FORMAT IS NOT DESIGNED FOR DATA INTERCHANGE. This
22 +# implementation is provided for convenience and demonstrational
23 +# purposes only.
24 +
25 +
26 +from . import ImageFile, ImagePalette
27 +from ._binary import i8, i16be as i16, i32be as i32
28 +
29 +# __version__ is deprecated and will be removed in a future version. Use
30 +# PIL.__version__ instead.
31 +__version__ = "0.1"
32 +
33 +
34 +##
35 +# Image plugin for the GD uncompressed format. Note that this format
36 +# is not supported by the standard <b>Image.open</b> function. To use
37 +# this plugin, you have to import the <b>GdImageFile</b> module and
38 +# use the <b>GdImageFile.open</b> function.
39 +
40 +
41 +class GdImageFile(ImageFile.ImageFile):
42 +
43 + format = "GD"
44 + format_description = "GD uncompressed images"
45 +
46 + def _open(self):
47 +
48 + # Header
49 + s = self.fp.read(1037)
50 +
51 + if not i16(s[:2]) in [65534, 65535]:
52 + raise SyntaxError("Not a valid GD 2.x .gd file")
53 +
54 + self.mode = "L" # FIXME: "P"
55 + self._size = i16(s[2:4]), i16(s[4:6])
56 +
57 + trueColor = i8(s[6])
58 + trueColorOffset = 2 if trueColor else 0
59 +
60 + # transparency index
61 + tindex = i32(s[7 + trueColorOffset : 7 + trueColorOffset + 4])
62 + if tindex < 256:
63 + self.info["transparency"] = tindex
64 +
65 + self.palette = ImagePalette.raw(
66 + "XBGR", s[7 + trueColorOffset + 4 : 7 + trueColorOffset + 4 + 256 * 4]
67 + )
68 +
69 + self.tile = [
70 + ("raw", (0, 0) + self.size, 7 + trueColorOffset + 4 + 256 * 4, ("L", 0, 1))
71 + ]
72 +
73 +
74 +def open(fp, mode="r"):
75 + """
76 + Load texture from a GD image file.
77 +
78 + :param filename: GD file name, or an opened file handle.
79 + :param mode: Optional mode. In this version, if the mode argument
80 + is given, it must be "r".
81 + :returns: An image instance.
82 + :raises IOError: If the image could not be read.
83 + """
84 + if mode != "r":
85 + raise ValueError("bad mode")
86 +
87 + try:
88 + return GdImageFile(fp)
89 + except SyntaxError:
90 + raise IOError("cannot identify this image file")
This diff is collapsed. Click to expand it.
1 +#
2 +# Python Imaging Library
3 +# $Id$
4 +#
5 +# stuff to read (and render) GIMP gradient files
6 +#
7 +# History:
8 +# 97-08-23 fl Created
9 +#
10 +# Copyright (c) Secret Labs AB 1997.
11 +# Copyright (c) Fredrik Lundh 1997.
12 +#
13 +# See the README file for information on usage and redistribution.
14 +#
15 +
16 +from math import log, pi, sin, sqrt
17 +
18 +from ._binary import o8
19 +
20 +# --------------------------------------------------------------------
21 +# Stuff to translate curve segments to palette values (derived from
22 +# the corresponding code in GIMP, written by Federico Mena Quintero.
23 +# See the GIMP distribution for more information.)
24 +#
25 +
26 +EPSILON = 1e-10
27 +
28 +
29 +def linear(middle, pos):
30 + if pos <= middle:
31 + if middle < EPSILON:
32 + return 0.0
33 + else:
34 + return 0.5 * pos / middle
35 + else:
36 + pos = pos - middle
37 + middle = 1.0 - middle
38 + if middle < EPSILON:
39 + return 1.0
40 + else:
41 + return 0.5 + 0.5 * pos / middle
42 +
43 +
44 +def curved(middle, pos):
45 + return pos ** (log(0.5) / log(max(middle, EPSILON)))
46 +
47 +
48 +def sine(middle, pos):
49 + return (sin((-pi / 2.0) + pi * linear(middle, pos)) + 1.0) / 2.0
50 +
51 +
52 +def sphere_increasing(middle, pos):
53 + return sqrt(1.0 - (linear(middle, pos) - 1.0) ** 2)
54 +
55 +
56 +def sphere_decreasing(middle, pos):
57 + return 1.0 - sqrt(1.0 - linear(middle, pos) ** 2)
58 +
59 +
60 +SEGMENTS = [linear, curved, sine, sphere_increasing, sphere_decreasing]
61 +
62 +
63 +class GradientFile(object):
64 +
65 + gradient = None
66 +
67 + def getpalette(self, entries=256):
68 +
69 + palette = []
70 +
71 + ix = 0
72 + x0, x1, xm, rgb0, rgb1, segment = self.gradient[ix]
73 +
74 + for i in range(entries):
75 +
76 + x = i / float(entries - 1)
77 +
78 + while x1 < x:
79 + ix += 1
80 + x0, x1, xm, rgb0, rgb1, segment = self.gradient[ix]
81 +
82 + w = x1 - x0
83 +
84 + if w < EPSILON:
85 + scale = segment(0.5, 0.5)
86 + else:
87 + scale = segment((xm - x0) / w, (x - x0) / w)
88 +
89 + # expand to RGBA
90 + r = o8(int(255 * ((rgb1[0] - rgb0[0]) * scale + rgb0[0]) + 0.5))
91 + g = o8(int(255 * ((rgb1[1] - rgb0[1]) * scale + rgb0[1]) + 0.5))
92 + b = o8(int(255 * ((rgb1[2] - rgb0[2]) * scale + rgb0[2]) + 0.5))
93 + a = o8(int(255 * ((rgb1[3] - rgb0[3]) * scale + rgb0[3]) + 0.5))
94 +
95 + # add to palette
96 + palette.append(r + g + b + a)
97 +
98 + return b"".join(palette), "RGBA"
99 +
100 +
101 +##
102 +# File handler for GIMP's gradient format.
103 +
104 +
105 +class GimpGradientFile(GradientFile):
106 + def __init__(self, fp):
107 +
108 + if fp.readline()[:13] != b"GIMP Gradient":
109 + raise SyntaxError("not a GIMP gradient file")
110 +
111 + line = fp.readline()
112 +
113 + # GIMP 1.2 gradient files don't contain a name, but GIMP 1.3 files do
114 + if line.startswith(b"Name: "):
115 + line = fp.readline().strip()
116 +
117 + count = int(line)
118 +
119 + gradient = []
120 +
121 + for i in range(count):
122 +
123 + s = fp.readline().split()
124 + w = [float(x) for x in s[:11]]
125 +
126 + x0, x1 = w[0], w[2]
127 + xm = w[1]
128 + rgb0 = w[3:7]
129 + rgb1 = w[7:11]
130 +
131 + segment = SEGMENTS[int(s[11])]
132 + cspace = int(s[12])
133 +
134 + if cspace != 0:
135 + raise IOError("cannot handle HSV colour space")
136 +
137 + gradient.append((x0, x1, xm, rgb0, rgb1, segment))
138 +
139 + self.gradient = gradient
1 +#
2 +# Python Imaging Library
3 +# $Id$
4 +#
5 +# stuff to read GIMP palette files
6 +#
7 +# History:
8 +# 1997-08-23 fl Created
9 +# 2004-09-07 fl Support GIMP 2.0 palette files.
10 +#
11 +# Copyright (c) Secret Labs AB 1997-2004. All rights reserved.
12 +# Copyright (c) Fredrik Lundh 1997-2004.
13 +#
14 +# See the README file for information on usage and redistribution.
15 +#
16 +
17 +import re
18 +
19 +from ._binary import o8
20 +
21 +##
22 +# File handler for GIMP's palette format.
23 +
24 +
25 +class GimpPaletteFile(object):
26 +
27 + rawmode = "RGB"
28 +
29 + def __init__(self, fp):
30 +
31 + self.palette = [o8(i) * 3 for i in range(256)]
32 +
33 + if fp.readline()[:12] != b"GIMP Palette":
34 + raise SyntaxError("not a GIMP palette file")
35 +
36 + for i in range(256):
37 +
38 + s = fp.readline()
39 + if not s:
40 + break
41 +
42 + # skip fields and comment lines
43 + if re.match(br"\w+:|#", s):
44 + continue
45 + if len(s) > 100:
46 + raise SyntaxError("bad palette file")
47 +
48 + v = tuple(map(int, s.split()[:3]))
49 + if len(v) != 3:
50 + raise ValueError("bad palette entry")
51 +
52 + self.palette[i] = o8(v[0]) + o8(v[1]) + o8(v[2])
53 +
54 + self.palette = b"".join(self.palette)
55 +
56 + def getpalette(self):
57 +
58 + return self.palette, self.rawmode
1 +#
2 +# The Python Imaging Library
3 +# $Id$
4 +#
5 +# GRIB stub adapter
6 +#
7 +# Copyright (c) 1996-2003 by Fredrik Lundh
8 +#
9 +# See the README file for information on usage and redistribution.
10 +#
11 +
12 +from . import Image, ImageFile
13 +from ._binary import i8
14 +
15 +_handler = None
16 +
17 +
18 +def register_handler(handler):
19 + """
20 + Install application-specific GRIB image handler.
21 +
22 + :param handler: Handler object.
23 + """
24 + global _handler
25 + _handler = handler
26 +
27 +
28 +# --------------------------------------------------------------------
29 +# Image adapter
30 +
31 +
32 +def _accept(prefix):
33 + return prefix[0:4] == b"GRIB" and i8(prefix[7]) == 1
34 +
35 +
36 +class GribStubImageFile(ImageFile.StubImageFile):
37 +
38 + format = "GRIB"
39 + format_description = "GRIB"
40 +
41 + def _open(self):
42 +
43 + offset = self.fp.tell()
44 +
45 + if not _accept(self.fp.read(8)):
46 + raise SyntaxError("Not a GRIB file")
47 +
48 + self.fp.seek(offset)
49 +
50 + # make something up
51 + self.mode = "F"
52 + self._size = 1, 1
53 +
54 + loader = self._load()
55 + if loader:
56 + loader.open(self)
57 +
58 + def _load(self):
59 + return _handler
60 +
61 +
62 +def _save(im, fp, filename):
63 + if _handler is None or not hasattr("_handler", "save"):
64 + raise IOError("GRIB save handler not installed")
65 + _handler.save(im, fp, filename)
66 +
67 +
68 +# --------------------------------------------------------------------
69 +# Registry
70 +
71 +Image.register_open(GribStubImageFile.format, GribStubImageFile, _accept)
72 +Image.register_save(GribStubImageFile.format, _save)
73 +
74 +Image.register_extension(GribStubImageFile.format, ".grib")
1 +#
2 +# The Python Imaging Library
3 +# $Id$
4 +#
5 +# HDF5 stub adapter
6 +#
7 +# Copyright (c) 2000-2003 by Fredrik Lundh
8 +#
9 +# See the README file for information on usage and redistribution.
10 +#
11 +
12 +from . import Image, ImageFile
13 +
14 +_handler = None
15 +
16 +
17 +def register_handler(handler):
18 + """
19 + Install application-specific HDF5 image handler.
20 +
21 + :param handler: Handler object.
22 + """
23 + global _handler
24 + _handler = handler
25 +
26 +
27 +# --------------------------------------------------------------------
28 +# Image adapter
29 +
30 +
31 +def _accept(prefix):
32 + return prefix[:8] == b"\x89HDF\r\n\x1a\n"
33 +
34 +
35 +class HDF5StubImageFile(ImageFile.StubImageFile):
36 +
37 + format = "HDF5"
38 + format_description = "HDF5"
39 +
40 + def _open(self):
41 +
42 + offset = self.fp.tell()
43 +
44 + if not _accept(self.fp.read(8)):
45 + raise SyntaxError("Not an HDF file")
46 +
47 + self.fp.seek(offset)
48 +
49 + # make something up
50 + self.mode = "F"
51 + self._size = 1, 1
52 +
53 + loader = self._load()
54 + if loader:
55 + loader.open(self)
56 +
57 + def _load(self):
58 + return _handler
59 +
60 +
61 +def _save(im, fp, filename):
62 + if _handler is None or not hasattr("_handler", "save"):
63 + raise IOError("HDF5 save handler not installed")
64 + _handler.save(im, fp, filename)
65 +
66 +
67 +# --------------------------------------------------------------------
68 +# Registry
69 +
70 +Image.register_open(HDF5StubImageFile.format, HDF5StubImageFile, _accept)
71 +Image.register_save(HDF5StubImageFile.format, _save)
72 +
73 +Image.register_extensions(HDF5StubImageFile.format, [".h5", ".hdf"])
This diff is collapsed. Click to expand it.
1 +#
2 +# The Python Imaging Library.
3 +# $Id$
4 +#
5 +# Windows Icon support for PIL
6 +#
7 +# History:
8 +# 96-05-27 fl Created
9 +#
10 +# Copyright (c) Secret Labs AB 1997.
11 +# Copyright (c) Fredrik Lundh 1996.
12 +#
13 +# See the README file for information on usage and redistribution.
14 +#
15 +
16 +# This plugin is a refactored version of Win32IconImagePlugin by Bryan Davis
17 +# <casadebender@gmail.com>.
18 +# https://code.google.com/archive/p/casadebender/wikis/Win32IconImagePlugin.wiki
19 +#
20 +# Icon format references:
21 +# * https://en.wikipedia.org/wiki/ICO_(file_format)
22 +# * https://msdn.microsoft.com/en-us/library/ms997538.aspx
23 +
24 +
25 +import struct
26 +import warnings
27 +from io import BytesIO
28 +from math import ceil, log
29 +
30 +from . import BmpImagePlugin, Image, ImageFile, PngImagePlugin
31 +from ._binary import i8, i16le as i16, i32le as i32
32 +
33 +# __version__ is deprecated and will be removed in a future version. Use
34 +# PIL.__version__ instead.
35 +__version__ = "0.1"
36 +
37 +#
38 +# --------------------------------------------------------------------
39 +
40 +_MAGIC = b"\0\0\1\0"
41 +
42 +
43 +def _save(im, fp, filename):
44 + fp.write(_MAGIC) # (2+2)
45 + sizes = im.encoderinfo.get(
46 + "sizes",
47 + [(16, 16), (24, 24), (32, 32), (48, 48), (64, 64), (128, 128), (256, 256)],
48 + )
49 + width, height = im.size
50 + sizes = filter(
51 + lambda x: False
52 + if (x[0] > width or x[1] > height or x[0] > 256 or x[1] > 256)
53 + else True,
54 + sizes,
55 + )
56 + sizes = list(sizes)
57 + fp.write(struct.pack("<H", len(sizes))) # idCount(2)
58 + offset = fp.tell() + len(sizes) * 16
59 + for size in sizes:
60 + width, height = size
61 + # 0 means 256
62 + fp.write(struct.pack("B", width if width < 256 else 0)) # bWidth(1)
63 + fp.write(struct.pack("B", height if height < 256 else 0)) # bHeight(1)
64 + fp.write(b"\0") # bColorCount(1)
65 + fp.write(b"\0") # bReserved(1)
66 + fp.write(b"\0\0") # wPlanes(2)
67 + fp.write(struct.pack("<H", 32)) # wBitCount(2)
68 +
69 + image_io = BytesIO()
70 + tmp = im.copy()
71 + tmp.thumbnail(size, Image.LANCZOS)
72 + tmp.save(image_io, "png")
73 + image_io.seek(0)
74 + image_bytes = image_io.read()
75 + bytes_len = len(image_bytes)
76 + fp.write(struct.pack("<I", bytes_len)) # dwBytesInRes(4)
77 + fp.write(struct.pack("<I", offset)) # dwImageOffset(4)
78 + current = fp.tell()
79 + fp.seek(offset)
80 + fp.write(image_bytes)
81 + offset = offset + bytes_len
82 + fp.seek(current)
83 +
84 +
85 +def _accept(prefix):
86 + return prefix[:4] == _MAGIC
87 +
88 +
89 +class IcoFile(object):
90 + def __init__(self, buf):
91 + """
92 + Parse image from file-like object containing ico file data
93 + """
94 +
95 + # check magic
96 + s = buf.read(6)
97 + if not _accept(s):
98 + raise SyntaxError("not an ICO file")
99 +
100 + self.buf = buf
101 + self.entry = []
102 +
103 + # Number of items in file
104 + self.nb_items = i16(s[4:])
105 +
106 + # Get headers for each item
107 + for i in range(self.nb_items):
108 + s = buf.read(16)
109 +
110 + icon_header = {
111 + "width": i8(s[0]),
112 + "height": i8(s[1]),
113 + "nb_color": i8(s[2]), # No. of colors in image (0 if >=8bpp)
114 + "reserved": i8(s[3]),
115 + "planes": i16(s[4:]),
116 + "bpp": i16(s[6:]),
117 + "size": i32(s[8:]),
118 + "offset": i32(s[12:]),
119 + }
120 +
121 + # See Wikipedia
122 + for j in ("width", "height"):
123 + if not icon_header[j]:
124 + icon_header[j] = 256
125 +
126 + # See Wikipedia notes about color depth.
127 + # We need this just to differ images with equal sizes
128 + icon_header["color_depth"] = (
129 + icon_header["bpp"]
130 + or (
131 + icon_header["nb_color"] != 0
132 + and ceil(log(icon_header["nb_color"], 2))
133 + )
134 + or 256
135 + )
136 +
137 + icon_header["dim"] = (icon_header["width"], icon_header["height"])
138 + icon_header["square"] = icon_header["width"] * icon_header["height"]
139 +
140 + self.entry.append(icon_header)
141 +
142 + self.entry = sorted(self.entry, key=lambda x: x["color_depth"])
143 + # ICO images are usually squares
144 + # self.entry = sorted(self.entry, key=lambda x: x['width'])
145 + self.entry = sorted(self.entry, key=lambda x: x["square"])
146 + self.entry.reverse()
147 +
148 + def sizes(self):
149 + """
150 + Get a list of all available icon sizes and color depths.
151 + """
152 + return {(h["width"], h["height"]) for h in self.entry}
153 +
154 + def getentryindex(self, size, bpp=False):
155 + for (i, h) in enumerate(self.entry):
156 + if size == h["dim"] and (bpp is False or bpp == h["color_depth"]):
157 + return i
158 + return 0
159 +
160 + def getimage(self, size, bpp=False):
161 + """
162 + Get an image from the icon
163 + """
164 + return self.frame(self.getentryindex(size, bpp))
165 +
166 + def frame(self, idx):
167 + """
168 + Get an image from frame idx
169 + """
170 +
171 + header = self.entry[idx]
172 +
173 + self.buf.seek(header["offset"])
174 + data = self.buf.read(8)
175 + self.buf.seek(header["offset"])
176 +
177 + if data[:8] == PngImagePlugin._MAGIC:
178 + # png frame
179 + im = PngImagePlugin.PngImageFile(self.buf)
180 + else:
181 + # XOR + AND mask bmp frame
182 + im = BmpImagePlugin.DibImageFile(self.buf)
183 + Image._decompression_bomb_check(im.size)
184 +
185 + # change tile dimension to only encompass XOR image
186 + im._size = (im.size[0], int(im.size[1] / 2))
187 + d, e, o, a = im.tile[0]
188 + im.tile[0] = d, (0, 0) + im.size, o, a
189 +
190 + # figure out where AND mask image starts
191 + mode = a[0]
192 + bpp = 8
193 + for k, v in BmpImagePlugin.BIT2MODE.items():
194 + if mode == v[1]:
195 + bpp = k
196 + break
197 +
198 + if 32 == bpp:
199 + # 32-bit color depth icon image allows semitransparent areas
200 + # PIL's DIB format ignores transparency bits, recover them.
201 + # The DIB is packed in BGRX byte order where X is the alpha
202 + # channel.
203 +
204 + # Back up to start of bmp data
205 + self.buf.seek(o)
206 + # extract every 4th byte (eg. 3,7,11,15,...)
207 + alpha_bytes = self.buf.read(im.size[0] * im.size[1] * 4)[3::4]
208 +
209 + # convert to an 8bpp grayscale image
210 + mask = Image.frombuffer(
211 + "L", # 8bpp
212 + im.size, # (w, h)
213 + alpha_bytes, # source chars
214 + "raw", # raw decoder
215 + ("L", 0, -1), # 8bpp inverted, unpadded, reversed
216 + )
217 + else:
218 + # get AND image from end of bitmap
219 + w = im.size[0]
220 + if (w % 32) > 0:
221 + # bitmap row data is aligned to word boundaries
222 + w += 32 - (im.size[0] % 32)
223 +
224 + # the total mask data is
225 + # padded row size * height / bits per char
226 +
227 + and_mask_offset = o + int(im.size[0] * im.size[1] * (bpp / 8.0))
228 + total_bytes = int((w * im.size[1]) / 8)
229 +
230 + self.buf.seek(and_mask_offset)
231 + mask_data = self.buf.read(total_bytes)
232 +
233 + # convert raw data to image
234 + mask = Image.frombuffer(
235 + "1", # 1 bpp
236 + im.size, # (w, h)
237 + mask_data, # source chars
238 + "raw", # raw decoder
239 + ("1;I", int(w / 8), -1), # 1bpp inverted, padded, reversed
240 + )
241 +
242 + # now we have two images, im is XOR image and mask is AND image
243 +
244 + # apply mask image as alpha channel
245 + im = im.convert("RGBA")
246 + im.putalpha(mask)
247 +
248 + return im
249 +
250 +
251 +##
252 +# Image plugin for Windows Icon files.
253 +
254 +
255 +class IcoImageFile(ImageFile.ImageFile):
256 + """
257 + PIL read-only image support for Microsoft Windows .ico files.
258 +
259 + By default the largest resolution image in the file will be loaded. This
260 + can be changed by altering the 'size' attribute before calling 'load'.
261 +
262 + The info dictionary has a key 'sizes' that is a list of the sizes available
263 + in the icon file.
264 +
265 + Handles classic, XP and Vista icon formats.
266 +
267 + When saving, PNG compression is used. Support for this was only added in
268 + Windows Vista.
269 +
270 + This plugin is a refactored version of Win32IconImagePlugin by Bryan Davis
271 + <casadebender@gmail.com>.
272 + https://code.google.com/archive/p/casadebender/wikis/Win32IconImagePlugin.wiki
273 + """
274 +
275 + format = "ICO"
276 + format_description = "Windows Icon"
277 +
278 + def _open(self):
279 + self.ico = IcoFile(self.fp)
280 + self.info["sizes"] = self.ico.sizes()
281 + self.size = self.ico.entry[0]["dim"]
282 + self.load()
283 +
284 + @property
285 + def size(self):
286 + return self._size
287 +
288 + @size.setter
289 + def size(self, value):
290 + if value not in self.info["sizes"]:
291 + raise ValueError("This is not one of the allowed sizes of this image")
292 + self._size = value
293 +
294 + def load(self):
295 + if self.im and self.im.size == self.size:
296 + # Already loaded
297 + return
298 + im = self.ico.getimage(self.size)
299 + # if tile is PNG, it won't really be loaded yet
300 + im.load()
301 + self.im = im.im
302 + self.mode = im.mode
303 + if im.size != self.size:
304 + warnings.warn("Image was not the expected size")
305 +
306 + index = self.ico.getentryindex(self.size)
307 + sizes = list(self.info["sizes"])
308 + sizes[index] = im.size
309 + self.info["sizes"] = set(sizes)
310 +
311 + self.size = im.size
312 +
313 + def load_seek(self):
314 + # Flag the ImageFile.Parser so that it
315 + # just does all the decode at the end.
316 + pass
317 +
318 +
319 +#
320 +# --------------------------------------------------------------------
321 +
322 +
323 +Image.register_open(IcoImageFile.format, IcoImageFile, _accept)
324 +Image.register_save(IcoImageFile.format, _save)
325 +Image.register_extension(IcoImageFile.format, ".ico")
326 +
327 +Image.register_mime(IcoImageFile.format, "image/x-icon")
This diff is collapsed. Click to expand it.
This diff could not be displayed because it is too large.
1 +#
2 +# The Python Imaging Library.
3 +# $Id$
4 +#
5 +# standard channel operations
6 +#
7 +# History:
8 +# 1996-03-24 fl Created
9 +# 1996-08-13 fl Added logical operations (for "1" images)
10 +# 2000-10-12 fl Added offset method (from Image.py)
11 +#
12 +# Copyright (c) 1997-2000 by Secret Labs AB
13 +# Copyright (c) 1996-2000 by Fredrik Lundh
14 +#
15 +# See the README file for information on usage and redistribution.
16 +#
17 +
18 +from . import Image
19 +
20 +
21 +def constant(image, value):
22 + """Fill a channel with a given grey level.
23 +
24 + :rtype: :py:class:`~PIL.Image.Image`
25 + """
26 +
27 + return Image.new("L", image.size, value)
28 +
29 +
30 +def duplicate(image):
31 + """Copy a channel. Alias for :py:meth:`PIL.Image.Image.copy`.
32 +
33 + :rtype: :py:class:`~PIL.Image.Image`
34 + """
35 +
36 + return image.copy()
37 +
38 +
39 +def invert(image):
40 + """
41 + Invert an image (channel).
42 +
43 + .. code-block:: python
44 +
45 + out = MAX - image
46 +
47 + :rtype: :py:class:`~PIL.Image.Image`
48 + """
49 +
50 + image.load()
51 + return image._new(image.im.chop_invert())
52 +
53 +
54 +def lighter(image1, image2):
55 + """
56 + Compares the two images, pixel by pixel, and returns a new image containing
57 + the lighter values. At least one of the images must have mode "1".
58 +
59 + .. code-block:: python
60 +
61 + out = max(image1, image2)
62 +
63 + :rtype: :py:class:`~PIL.Image.Image`
64 + """
65 +
66 + image1.load()
67 + image2.load()
68 + return image1._new(image1.im.chop_lighter(image2.im))
69 +
70 +
71 +def darker(image1, image2):
72 + """
73 + Compares the two images, pixel by pixel, and returns a new image containing
74 + the darker values. At least one of the images must have mode "1".
75 +
76 + .. code-block:: python
77 +
78 + out = min(image1, image2)
79 +
80 + :rtype: :py:class:`~PIL.Image.Image`
81 + """
82 +
83 + image1.load()
84 + image2.load()
85 + return image1._new(image1.im.chop_darker(image2.im))
86 +
87 +
88 +def difference(image1, image2):
89 + """
90 + Returns the absolute value of the pixel-by-pixel difference between the two
91 + images. At least one of the images must have mode "1".
92 +
93 + .. code-block:: python
94 +
95 + out = abs(image1 - image2)
96 +
97 + :rtype: :py:class:`~PIL.Image.Image`
98 + """
99 +
100 + image1.load()
101 + image2.load()
102 + return image1._new(image1.im.chop_difference(image2.im))
103 +
104 +
105 +def multiply(image1, image2):
106 + """
107 + Superimposes two images on top of each other.
108 +
109 + If you multiply an image with a solid black image, the result is black. If
110 + you multiply with a solid white image, the image is unaffected. At least
111 + one of the images must have mode "1".
112 +
113 + .. code-block:: python
114 +
115 + out = image1 * image2 / MAX
116 +
117 + :rtype: :py:class:`~PIL.Image.Image`
118 + """
119 +
120 + image1.load()
121 + image2.load()
122 + return image1._new(image1.im.chop_multiply(image2.im))
123 +
124 +
125 +def screen(image1, image2):
126 + """
127 + Superimposes two inverted images on top of each other. At least one of the
128 + images must have mode "1".
129 +
130 + .. code-block:: python
131 +
132 + out = MAX - ((MAX - image1) * (MAX - image2) / MAX)
133 +
134 + :rtype: :py:class:`~PIL.Image.Image`
135 + """
136 +
137 + image1.load()
138 + image2.load()
139 + return image1._new(image1.im.chop_screen(image2.im))
140 +
141 +
142 +def add(image1, image2, scale=1.0, offset=0):
143 + """
144 + Adds two images, dividing the result by scale and adding the
145 + offset. If omitted, scale defaults to 1.0, and offset to 0.0.
146 + At least one of the images must have mode "1".
147 +
148 + .. code-block:: python
149 +
150 + out = ((image1 + image2) / scale + offset)
151 +
152 + :rtype: :py:class:`~PIL.Image.Image`
153 + """
154 +
155 + image1.load()
156 + image2.load()
157 + return image1._new(image1.im.chop_add(image2.im, scale, offset))
158 +
159 +
160 +def subtract(image1, image2, scale=1.0, offset=0):
161 + """
162 + Subtracts two images, dividing the result by scale and adding the offset.
163 + If omitted, scale defaults to 1.0, and offset to 0.0. At least one of the
164 + images must have mode "1".
165 +
166 + .. code-block:: python
167 +
168 + out = ((image1 - image2) / scale + offset)
169 +
170 + :rtype: :py:class:`~PIL.Image.Image`
171 + """
172 +
173 + image1.load()
174 + image2.load()
175 + return image1._new(image1.im.chop_subtract(image2.im, scale, offset))
176 +
177 +
178 +def add_modulo(image1, image2):
179 + """Add two images, without clipping the result. At least one of the images
180 + must have mode "1".
181 +
182 + .. code-block:: python
183 +
184 + out = ((image1 + image2) % MAX)
185 +
186 + :rtype: :py:class:`~PIL.Image.Image`
187 + """
188 +
189 + image1.load()
190 + image2.load()
191 + return image1._new(image1.im.chop_add_modulo(image2.im))
192 +
193 +
194 +def subtract_modulo(image1, image2):
195 + """Subtract two images, without clipping the result. At least one of the
196 + images must have mode "1".
197 +
198 + .. code-block:: python
199 +
200 + out = ((image1 - image2) % MAX)
201 +
202 + :rtype: :py:class:`~PIL.Image.Image`
203 + """
204 +
205 + image1.load()
206 + image2.load()
207 + return image1._new(image1.im.chop_subtract_modulo(image2.im))
208 +
209 +
210 +def logical_and(image1, image2):
211 + """Logical AND between two images. At least one of the images must have
212 + mode "1".
213 +
214 + .. code-block:: python
215 +
216 + out = ((image1 and image2) % MAX)
217 +
218 + :rtype: :py:class:`~PIL.Image.Image`
219 + """
220 +
221 + image1.load()
222 + image2.load()
223 + return image1._new(image1.im.chop_and(image2.im))
224 +
225 +
226 +def logical_or(image1, image2):
227 + """Logical OR between two images. At least one of the images must have
228 + mode "1".
229 +
230 + .. code-block:: python
231 +
232 + out = ((image1 or image2) % MAX)
233 +
234 + :rtype: :py:class:`~PIL.Image.Image`
235 + """
236 +
237 + image1.load()
238 + image2.load()
239 + return image1._new(image1.im.chop_or(image2.im))
240 +
241 +
242 +def logical_xor(image1, image2):
243 + """Logical XOR between two images. At least one of the images must have
244 + mode "1".
245 +
246 + .. code-block:: python
247 +
248 + out = ((bool(image1) != bool(image2)) % MAX)
249 +
250 + :rtype: :py:class:`~PIL.Image.Image`
251 + """
252 +
253 + image1.load()
254 + image2.load()
255 + return image1._new(image1.im.chop_xor(image2.im))
256 +
257 +
258 +def blend(image1, image2, alpha):
259 + """Blend images using constant transparency weight. Alias for
260 + :py:meth:`PIL.Image.Image.blend`.
261 +
262 + :rtype: :py:class:`~PIL.Image.Image`
263 + """
264 +
265 + return Image.blend(image1, image2, alpha)
266 +
267 +
268 +def composite(image1, image2, mask):
269 + """Create composite using transparency mask. Alias for
270 + :py:meth:`PIL.Image.Image.composite`.
271 +
272 + :rtype: :py:class:`~PIL.Image.Image`
273 + """
274 +
275 + return Image.composite(image1, image2, mask)
276 +
277 +
278 +def offset(image, xoffset, yoffset=None):
279 + """Returns a copy of the image where data has been offset by the given
280 + distances. Data wraps around the edges. If **yoffset** is omitted, it
281 + is assumed to be equal to **xoffset**.
282 +
283 + :param xoffset: The horizontal distance.
284 + :param yoffset: The vertical distance. If omitted, both
285 + distances are set to the same value.
286 + :rtype: :py:class:`~PIL.Image.Image`
287 + """
288 +
289 + if yoffset is None:
290 + yoffset = xoffset
291 + image.load()
292 + return image._new(image.im.offset(xoffset, yoffset))
This diff is collapsed. Click to expand it.
1 +#
2 +# The Python Imaging Library
3 +# $Id$
4 +#
5 +# map CSS3-style colour description strings to RGB
6 +#
7 +# History:
8 +# 2002-10-24 fl Added support for CSS-style color strings
9 +# 2002-12-15 fl Added RGBA support
10 +# 2004-03-27 fl Fixed remaining int() problems for Python 1.5.2
11 +# 2004-07-19 fl Fixed gray/grey spelling issues
12 +# 2009-03-05 fl Fixed rounding error in grayscale calculation
13 +#
14 +# Copyright (c) 2002-2004 by Secret Labs AB
15 +# Copyright (c) 2002-2004 by Fredrik Lundh
16 +#
17 +# See the README file for information on usage and redistribution.
18 +#
19 +
20 +import re
21 +
22 +from . import Image
23 +
24 +
25 +def getrgb(color):
26 + """
27 + Convert a color string to an RGB tuple. If the string cannot be parsed,
28 + this function raises a :py:exc:`ValueError` exception.
29 +
30 + .. versionadded:: 1.1.4
31 +
32 + :param color: A color string
33 + :return: ``(red, green, blue[, alpha])``
34 + """
35 + color = color.lower()
36 +
37 + rgb = colormap.get(color, None)
38 + if rgb:
39 + if isinstance(rgb, tuple):
40 + return rgb
41 + colormap[color] = rgb = getrgb(rgb)
42 + return rgb
43 +
44 + # check for known string formats
45 + if re.match("#[a-f0-9]{3}$", color):
46 + return (int(color[1] * 2, 16), int(color[2] * 2, 16), int(color[3] * 2, 16))
47 +
48 + if re.match("#[a-f0-9]{4}$", color):
49 + return (
50 + int(color[1] * 2, 16),
51 + int(color[2] * 2, 16),
52 + int(color[3] * 2, 16),
53 + int(color[4] * 2, 16),
54 + )
55 +
56 + if re.match("#[a-f0-9]{6}$", color):
57 + return (int(color[1:3], 16), int(color[3:5], 16), int(color[5:7], 16))
58 +
59 + if re.match("#[a-f0-9]{8}$", color):
60 + return (
61 + int(color[1:3], 16),
62 + int(color[3:5], 16),
63 + int(color[5:7], 16),
64 + int(color[7:9], 16),
65 + )
66 +
67 + m = re.match(r"rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$", color)
68 + if m:
69 + return (int(m.group(1)), int(m.group(2)), int(m.group(3)))
70 +
71 + m = re.match(r"rgb\(\s*(\d+)%\s*,\s*(\d+)%\s*,\s*(\d+)%\s*\)$", color)
72 + if m:
73 + return (
74 + int((int(m.group(1)) * 255) / 100.0 + 0.5),
75 + int((int(m.group(2)) * 255) / 100.0 + 0.5),
76 + int((int(m.group(3)) * 255) / 100.0 + 0.5),
77 + )
78 +
79 + m = re.match(
80 + r"hsl\(\s*(\d+\.?\d*)\s*,\s*(\d+\.?\d*)%\s*,\s*(\d+\.?\d*)%\s*\)$", color
81 + )
82 + if m:
83 + from colorsys import hls_to_rgb
84 +
85 + rgb = hls_to_rgb(
86 + float(m.group(1)) / 360.0,
87 + float(m.group(3)) / 100.0,
88 + float(m.group(2)) / 100.0,
89 + )
90 + return (
91 + int(rgb[0] * 255 + 0.5),
92 + int(rgb[1] * 255 + 0.5),
93 + int(rgb[2] * 255 + 0.5),
94 + )
95 +
96 + m = re.match(
97 + r"hs[bv]\(\s*(\d+\.?\d*)\s*,\s*(\d+\.?\d*)%\s*,\s*(\d+\.?\d*)%\s*\)$", color
98 + )
99 + if m:
100 + from colorsys import hsv_to_rgb
101 +
102 + rgb = hsv_to_rgb(
103 + float(m.group(1)) / 360.0,
104 + float(m.group(2)) / 100.0,
105 + float(m.group(3)) / 100.0,
106 + )
107 + return (
108 + int(rgb[0] * 255 + 0.5),
109 + int(rgb[1] * 255 + 0.5),
110 + int(rgb[2] * 255 + 0.5),
111 + )
112 +
113 + m = re.match(r"rgba\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$", color)
114 + if m:
115 + return (int(m.group(1)), int(m.group(2)), int(m.group(3)), int(m.group(4)))
116 + raise ValueError("unknown color specifier: %r" % color)
117 +
118 +
119 +def getcolor(color, mode):
120 + """
121 + Same as :py:func:`~PIL.ImageColor.getrgb`, but converts the RGB value to a
122 + greyscale value if the mode is not color or a palette image. If the string
123 + cannot be parsed, this function raises a :py:exc:`ValueError` exception.
124 +
125 + .. versionadded:: 1.1.4
126 +
127 + :param color: A color string
128 + :return: ``(graylevel [, alpha]) or (red, green, blue[, alpha])``
129 + """
130 + # same as getrgb, but converts the result to the given mode
131 + color, alpha = getrgb(color), 255
132 + if len(color) == 4:
133 + color, alpha = color[0:3], color[3]
134 +
135 + if Image.getmodebase(mode) == "L":
136 + r, g, b = color
137 + color = (r * 299 + g * 587 + b * 114) // 1000
138 + if mode[-1] == "A":
139 + return (color, alpha)
140 + else:
141 + if mode[-1] == "A":
142 + return color + (alpha,)
143 + return color
144 +
145 +
146 +colormap = {
147 + # X11 colour table from https://drafts.csswg.org/css-color-4/, with
148 + # gray/grey spelling issues fixed. This is a superset of HTML 4.0
149 + # colour names used in CSS 1.
150 + "aliceblue": "#f0f8ff",
151 + "antiquewhite": "#faebd7",
152 + "aqua": "#00ffff",
153 + "aquamarine": "#7fffd4",
154 + "azure": "#f0ffff",
155 + "beige": "#f5f5dc",
156 + "bisque": "#ffe4c4",
157 + "black": "#000000",
158 + "blanchedalmond": "#ffebcd",
159 + "blue": "#0000ff",
160 + "blueviolet": "#8a2be2",
161 + "brown": "#a52a2a",
162 + "burlywood": "#deb887",
163 + "cadetblue": "#5f9ea0",
164 + "chartreuse": "#7fff00",
165 + "chocolate": "#d2691e",
166 + "coral": "#ff7f50",
167 + "cornflowerblue": "#6495ed",
168 + "cornsilk": "#fff8dc",
169 + "crimson": "#dc143c",
170 + "cyan": "#00ffff",
171 + "darkblue": "#00008b",
172 + "darkcyan": "#008b8b",
173 + "darkgoldenrod": "#b8860b",
174 + "darkgray": "#a9a9a9",
175 + "darkgrey": "#a9a9a9",
176 + "darkgreen": "#006400",
177 + "darkkhaki": "#bdb76b",
178 + "darkmagenta": "#8b008b",
179 + "darkolivegreen": "#556b2f",
180 + "darkorange": "#ff8c00",
181 + "darkorchid": "#9932cc",
182 + "darkred": "#8b0000",
183 + "darksalmon": "#e9967a",
184 + "darkseagreen": "#8fbc8f",
185 + "darkslateblue": "#483d8b",
186 + "darkslategray": "#2f4f4f",
187 + "darkslategrey": "#2f4f4f",
188 + "darkturquoise": "#00ced1",
189 + "darkviolet": "#9400d3",
190 + "deeppink": "#ff1493",
191 + "deepskyblue": "#00bfff",
192 + "dimgray": "#696969",
193 + "dimgrey": "#696969",
194 + "dodgerblue": "#1e90ff",
195 + "firebrick": "#b22222",
196 + "floralwhite": "#fffaf0",
197 + "forestgreen": "#228b22",
198 + "fuchsia": "#ff00ff",
199 + "gainsboro": "#dcdcdc",
200 + "ghostwhite": "#f8f8ff",
201 + "gold": "#ffd700",
202 + "goldenrod": "#daa520",
203 + "gray": "#808080",
204 + "grey": "#808080",
205 + "green": "#008000",
206 + "greenyellow": "#adff2f",
207 + "honeydew": "#f0fff0",
208 + "hotpink": "#ff69b4",
209 + "indianred": "#cd5c5c",
210 + "indigo": "#4b0082",
211 + "ivory": "#fffff0",
212 + "khaki": "#f0e68c",
213 + "lavender": "#e6e6fa",
214 + "lavenderblush": "#fff0f5",
215 + "lawngreen": "#7cfc00",
216 + "lemonchiffon": "#fffacd",
217 + "lightblue": "#add8e6",
218 + "lightcoral": "#f08080",
219 + "lightcyan": "#e0ffff",
220 + "lightgoldenrodyellow": "#fafad2",
221 + "lightgreen": "#90ee90",
222 + "lightgray": "#d3d3d3",
223 + "lightgrey": "#d3d3d3",
224 + "lightpink": "#ffb6c1",
225 + "lightsalmon": "#ffa07a",
226 + "lightseagreen": "#20b2aa",
227 + "lightskyblue": "#87cefa",
228 + "lightslategray": "#778899",
229 + "lightslategrey": "#778899",
230 + "lightsteelblue": "#b0c4de",
231 + "lightyellow": "#ffffe0",
232 + "lime": "#00ff00",
233 + "limegreen": "#32cd32",
234 + "linen": "#faf0e6",
235 + "magenta": "#ff00ff",
236 + "maroon": "#800000",
237 + "mediumaquamarine": "#66cdaa",
238 + "mediumblue": "#0000cd",
239 + "mediumorchid": "#ba55d3",
240 + "mediumpurple": "#9370db",
241 + "mediumseagreen": "#3cb371",
242 + "mediumslateblue": "#7b68ee",
243 + "mediumspringgreen": "#00fa9a",
244 + "mediumturquoise": "#48d1cc",
245 + "mediumvioletred": "#c71585",
246 + "midnightblue": "#191970",
247 + "mintcream": "#f5fffa",
248 + "mistyrose": "#ffe4e1",
249 + "moccasin": "#ffe4b5",
250 + "navajowhite": "#ffdead",
251 + "navy": "#000080",
252 + "oldlace": "#fdf5e6",
253 + "olive": "#808000",
254 + "olivedrab": "#6b8e23",
255 + "orange": "#ffa500",
256 + "orangered": "#ff4500",
257 + "orchid": "#da70d6",
258 + "palegoldenrod": "#eee8aa",
259 + "palegreen": "#98fb98",
260 + "paleturquoise": "#afeeee",
261 + "palevioletred": "#db7093",
262 + "papayawhip": "#ffefd5",
263 + "peachpuff": "#ffdab9",
264 + "peru": "#cd853f",
265 + "pink": "#ffc0cb",
266 + "plum": "#dda0dd",
267 + "powderblue": "#b0e0e6",
268 + "purple": "#800080",
269 + "rebeccapurple": "#663399",
270 + "red": "#ff0000",
271 + "rosybrown": "#bc8f8f",
272 + "royalblue": "#4169e1",
273 + "saddlebrown": "#8b4513",
274 + "salmon": "#fa8072",
275 + "sandybrown": "#f4a460",
276 + "seagreen": "#2e8b57",
277 + "seashell": "#fff5ee",
278 + "sienna": "#a0522d",
279 + "silver": "#c0c0c0",
280 + "skyblue": "#87ceeb",
281 + "slateblue": "#6a5acd",
282 + "slategray": "#708090",
283 + "slategrey": "#708090",
284 + "snow": "#fffafa",
285 + "springgreen": "#00ff7f",
286 + "steelblue": "#4682b4",
287 + "tan": "#d2b48c",
288 + "teal": "#008080",
289 + "thistle": "#d8bfd8",
290 + "tomato": "#ff6347",
291 + "turquoise": "#40e0d0",
292 + "violet": "#ee82ee",
293 + "wheat": "#f5deb3",
294 + "white": "#ffffff",
295 + "whitesmoke": "#f5f5f5",
296 + "yellow": "#ffff00",
297 + "yellowgreen": "#9acd32",
298 +}
This diff is collapsed. Click to expand it.
1 +#
2 +# The Python Imaging Library
3 +# $Id$
4 +#
5 +# WCK-style drawing interface operations
6 +#
7 +# History:
8 +# 2003-12-07 fl created
9 +# 2005-05-15 fl updated; added to PIL as ImageDraw2
10 +# 2005-05-15 fl added text support
11 +# 2005-05-20 fl added arc/chord/pieslice support
12 +#
13 +# Copyright (c) 2003-2005 by Secret Labs AB
14 +# Copyright (c) 2003-2005 by Fredrik Lundh
15 +#
16 +# See the README file for information on usage and redistribution.
17 +#
18 +
19 +from . import Image, ImageColor, ImageDraw, ImageFont, ImagePath
20 +
21 +
22 +class Pen(object):
23 + def __init__(self, color, width=1, opacity=255):
24 + self.color = ImageColor.getrgb(color)
25 + self.width = width
26 +
27 +
28 +class Brush(object):
29 + def __init__(self, color, opacity=255):
30 + self.color = ImageColor.getrgb(color)
31 +
32 +
33 +class Font(object):
34 + def __init__(self, color, file, size=12):
35 + # FIXME: add support for bitmap fonts
36 + self.color = ImageColor.getrgb(color)
37 + self.font = ImageFont.truetype(file, size)
38 +
39 +
40 +class Draw(object):
41 + def __init__(self, image, size=None, color=None):
42 + if not hasattr(image, "im"):
43 + image = Image.new(image, size, color)
44 + self.draw = ImageDraw.Draw(image)
45 + self.image = image
46 + self.transform = None
47 +
48 + def flush(self):
49 + return self.image
50 +
51 + def render(self, op, xy, pen, brush=None):
52 + # handle color arguments
53 + outline = fill = None
54 + width = 1
55 + if isinstance(pen, Pen):
56 + outline = pen.color
57 + width = pen.width
58 + elif isinstance(brush, Pen):
59 + outline = brush.color
60 + width = brush.width
61 + if isinstance(brush, Brush):
62 + fill = brush.color
63 + elif isinstance(pen, Brush):
64 + fill = pen.color
65 + # handle transformation
66 + if self.transform:
67 + xy = ImagePath.Path(xy)
68 + xy.transform(self.transform)
69 + # render the item
70 + if op == "line":
71 + self.draw.line(xy, fill=outline, width=width)
72 + else:
73 + getattr(self.draw, op)(xy, fill=fill, outline=outline)
74 +
75 + def settransform(self, offset):
76 + (xoffset, yoffset) = offset
77 + self.transform = (1, 0, xoffset, 0, 1, yoffset)
78 +
79 + def arc(self, xy, start, end, *options):
80 + self.render("arc", xy, start, end, *options)
81 +
82 + def chord(self, xy, start, end, *options):
83 + self.render("chord", xy, start, end, *options)
84 +
85 + def ellipse(self, xy, *options):
86 + self.render("ellipse", xy, *options)
87 +
88 + def line(self, xy, *options):
89 + self.render("line", xy, *options)
90 +
91 + def pieslice(self, xy, start, end, *options):
92 + self.render("pieslice", xy, start, end, *options)
93 +
94 + def polygon(self, xy, *options):
95 + self.render("polygon", xy, *options)
96 +
97 + def rectangle(self, xy, *options):
98 + self.render("rectangle", xy, *options)
99 +
100 + def text(self, xy, text, font):
101 + if self.transform:
102 + xy = ImagePath.Path(xy)
103 + xy.transform(self.transform)
104 + self.draw.text(xy, text, font=font.font, fill=font.color)
105 +
106 + def textsize(self, text, font):
107 + return self.draw.textsize(text, font=font.font)
1 +#
2 +# The Python Imaging Library.
3 +# $Id$
4 +#
5 +# image enhancement classes
6 +#
7 +# For a background, see "Image Processing By Interpolation and
8 +# Extrapolation", Paul Haeberli and Douglas Voorhies. Available
9 +# at http://www.graficaobscura.com/interp/index.html
10 +#
11 +# History:
12 +# 1996-03-23 fl Created
13 +# 2009-06-16 fl Fixed mean calculation
14 +#
15 +# Copyright (c) Secret Labs AB 1997.
16 +# Copyright (c) Fredrik Lundh 1996.
17 +#
18 +# See the README file for information on usage and redistribution.
19 +#
20 +
21 +from . import Image, ImageFilter, ImageStat
22 +
23 +
24 +class _Enhance(object):
25 + def enhance(self, factor):
26 + """
27 + Returns an enhanced image.
28 +
29 + :param factor: A floating point value controlling the enhancement.
30 + Factor 1.0 always returns a copy of the original image,
31 + lower factors mean less color (brightness, contrast,
32 + etc), and higher values more. There are no restrictions
33 + on this value.
34 + :rtype: :py:class:`~PIL.Image.Image`
35 + """
36 + return Image.blend(self.degenerate, self.image, factor)
37 +
38 +
39 +class Color(_Enhance):
40 + """Adjust image color balance.
41 +
42 + This class can be used to adjust the colour balance of an image, in
43 + a manner similar to the controls on a colour TV set. An enhancement
44 + factor of 0.0 gives a black and white image. A factor of 1.0 gives
45 + the original image.
46 + """
47 +
48 + def __init__(self, image):
49 + self.image = image
50 + self.intermediate_mode = "L"
51 + if "A" in image.getbands():
52 + self.intermediate_mode = "LA"
53 +
54 + self.degenerate = image.convert(self.intermediate_mode).convert(image.mode)
55 +
56 +
57 +class Contrast(_Enhance):
58 + """Adjust image contrast.
59 +
60 + This class can be used to control the contrast of an image, similar
61 + to the contrast control on a TV set. An enhancement factor of 0.0
62 + gives a solid grey image. A factor of 1.0 gives the original image.
63 + """
64 +
65 + def __init__(self, image):
66 + self.image = image
67 + mean = int(ImageStat.Stat(image.convert("L")).mean[0] + 0.5)
68 + self.degenerate = Image.new("L", image.size, mean).convert(image.mode)
69 +
70 + if "A" in image.getbands():
71 + self.degenerate.putalpha(image.getchannel("A"))
72 +
73 +
74 +class Brightness(_Enhance):
75 + """Adjust image brightness.
76 +
77 + This class can be used to control the brightness of an image. An
78 + enhancement factor of 0.0 gives a black image. A factor of 1.0 gives the
79 + original image.
80 + """
81 +
82 + def __init__(self, image):
83 + self.image = image
84 + self.degenerate = Image.new(image.mode, image.size, 0)
85 +
86 + if "A" in image.getbands():
87 + self.degenerate.putalpha(image.getchannel("A"))
88 +
89 +
90 +class Sharpness(_Enhance):
91 + """Adjust image sharpness.
92 +
93 + This class can be used to adjust the sharpness of an image. An
94 + enhancement factor of 0.0 gives a blurred image, a factor of 1.0 gives the
95 + original image, and a factor of 2.0 gives a sharpened image.
96 + """
97 +
98 + def __init__(self, image):
99 + self.image = image
100 + self.degenerate = image.filter(ImageFilter.SMOOTH)
101 +
102 + if "A" in image.getbands():
103 + self.degenerate.putalpha(image.getchannel("A"))
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
1 +#
2 +# The Python Imaging Library
3 +# $Id$
4 +#
5 +# screen grabber (macOS and Windows only)
6 +#
7 +# History:
8 +# 2001-04-26 fl created
9 +# 2001-09-17 fl use builtin driver, if present
10 +# 2002-11-19 fl added grabclipboard support
11 +#
12 +# Copyright (c) 2001-2002 by Secret Labs AB
13 +# Copyright (c) 2001-2002 by Fredrik Lundh
14 +#
15 +# See the README file for information on usage and redistribution.
16 +#
17 +
18 +import sys
19 +
20 +from . import Image
21 +
22 +if sys.platform == "win32":
23 + grabber = Image.core.grabscreen
24 +elif sys.platform == "darwin":
25 + import os
26 + import tempfile
27 + import subprocess
28 +else:
29 + raise ImportError("ImageGrab is macOS and Windows only")
30 +
31 +
32 +def grab(bbox=None, include_layered_windows=False, all_screens=False):
33 + if sys.platform == "darwin":
34 + fh, filepath = tempfile.mkstemp(".png")
35 + os.close(fh)
36 + subprocess.call(["screencapture", "-x", filepath])
37 + im = Image.open(filepath)
38 + im.load()
39 + os.unlink(filepath)
40 + if bbox:
41 + im = im.crop(bbox)
42 + else:
43 + offset, size, data = grabber(include_layered_windows, all_screens)
44 + im = Image.frombytes(
45 + "RGB",
46 + size,
47 + data,
48 + # RGB, 32-bit line padding, origin lower left corner
49 + "raw",
50 + "BGR",
51 + (size[0] * 3 + 3) & -4,
52 + -1,
53 + )
54 + if bbox:
55 + x0, y0 = offset
56 + left, top, right, bottom = bbox
57 + im = im.crop((left - x0, top - y0, right - x0, bottom - y0))
58 + return im
59 +
60 +
61 +def grabclipboard():
62 + if sys.platform == "darwin":
63 + fh, filepath = tempfile.mkstemp(".jpg")
64 + os.close(fh)
65 + commands = [
66 + 'set theFile to (open for access POSIX file "'
67 + + filepath
68 + + '" with write permission)',
69 + "try",
70 + " write (the clipboard as JPEG picture) to theFile",
71 + "end try",
72 + "close access theFile",
73 + ]
74 + script = ["osascript"]
75 + for command in commands:
76 + script += ["-e", command]
77 + subprocess.call(script)
78 +
79 + im = None
80 + if os.stat(filepath).st_size != 0:
81 + im = Image.open(filepath)
82 + im.load()
83 + os.unlink(filepath)
84 + return im
85 + else:
86 + data = Image.core.grabclipboard()
87 + if isinstance(data, bytes):
88 + from . import BmpImagePlugin
89 + import io
90 +
91 + return BmpImagePlugin.DibImageFile(io.BytesIO(data))
92 + return data
1 +#
2 +# The Python Imaging Library
3 +# $Id$
4 +#
5 +# a simple math add-on for the Python Imaging Library
6 +#
7 +# History:
8 +# 1999-02-15 fl Original PIL Plus release
9 +# 2005-05-05 fl Simplified and cleaned up for PIL 1.1.6
10 +# 2005-09-12 fl Fixed int() and float() for Python 2.4.1
11 +#
12 +# Copyright (c) 1999-2005 by Secret Labs AB
13 +# Copyright (c) 2005 by Fredrik Lundh
14 +#
15 +# See the README file for information on usage and redistribution.
16 +#
17 +
18 +from . import Image, _imagingmath
19 +from ._util import py3
20 +
21 +try:
22 + import builtins
23 +except ImportError:
24 + import __builtin__
25 +
26 + builtins = __builtin__
27 +
28 +VERBOSE = 0
29 +
30 +
31 +def _isconstant(v):
32 + return isinstance(v, (int, float))
33 +
34 +
35 +class _Operand(object):
36 + """Wraps an image operand, providing standard operators"""
37 +
38 + def __init__(self, im):
39 + self.im = im
40 +
41 + def __fixup(self, im1):
42 + # convert image to suitable mode
43 + if isinstance(im1, _Operand):
44 + # argument was an image.
45 + if im1.im.mode in ("1", "L"):
46 + return im1.im.convert("I")
47 + elif im1.im.mode in ("I", "F"):
48 + return im1.im
49 + else:
50 + raise ValueError("unsupported mode: %s" % im1.im.mode)
51 + else:
52 + # argument was a constant
53 + if _isconstant(im1) and self.im.mode in ("1", "L", "I"):
54 + return Image.new("I", self.im.size, im1)
55 + else:
56 + return Image.new("F", self.im.size, im1)
57 +
58 + def apply(self, op, im1, im2=None, mode=None):
59 + im1 = self.__fixup(im1)
60 + if im2 is None:
61 + # unary operation
62 + out = Image.new(mode or im1.mode, im1.size, None)
63 + im1.load()
64 + try:
65 + op = getattr(_imagingmath, op + "_" + im1.mode)
66 + except AttributeError:
67 + raise TypeError("bad operand type for '%s'" % op)
68 + _imagingmath.unop(op, out.im.id, im1.im.id)
69 + else:
70 + # binary operation
71 + im2 = self.__fixup(im2)
72 + if im1.mode != im2.mode:
73 + # convert both arguments to floating point
74 + if im1.mode != "F":
75 + im1 = im1.convert("F")
76 + if im2.mode != "F":
77 + im2 = im2.convert("F")
78 + if im1.mode != im2.mode:
79 + raise ValueError("mode mismatch")
80 + if im1.size != im2.size:
81 + # crop both arguments to a common size
82 + size = (min(im1.size[0], im2.size[0]), min(im1.size[1], im2.size[1]))
83 + if im1.size != size:
84 + im1 = im1.crop((0, 0) + size)
85 + if im2.size != size:
86 + im2 = im2.crop((0, 0) + size)
87 + out = Image.new(mode or im1.mode, size, None)
88 + else:
89 + out = Image.new(mode or im1.mode, im1.size, None)
90 + im1.load()
91 + im2.load()
92 + try:
93 + op = getattr(_imagingmath, op + "_" + im1.mode)
94 + except AttributeError:
95 + raise TypeError("bad operand type for '%s'" % op)
96 + _imagingmath.binop(op, out.im.id, im1.im.id, im2.im.id)
97 + return _Operand(out)
98 +
99 + # unary operators
100 + def __bool__(self):
101 + # an image is "true" if it contains at least one non-zero pixel
102 + return self.im.getbbox() is not None
103 +
104 + if not py3:
105 + # Provide __nonzero__ for pre-Py3k
106 + __nonzero__ = __bool__
107 + del __bool__
108 +
109 + def __abs__(self):
110 + return self.apply("abs", self)
111 +
112 + def __pos__(self):
113 + return self
114 +
115 + def __neg__(self):
116 + return self.apply("neg", self)
117 +
118 + # binary operators
119 + def __add__(self, other):
120 + return self.apply("add", self, other)
121 +
122 + def __radd__(self, other):
123 + return self.apply("add", other, self)
124 +
125 + def __sub__(self, other):
126 + return self.apply("sub", self, other)
127 +
128 + def __rsub__(self, other):
129 + return self.apply("sub", other, self)
130 +
131 + def __mul__(self, other):
132 + return self.apply("mul", self, other)
133 +
134 + def __rmul__(self, other):
135 + return self.apply("mul", other, self)
136 +
137 + def __truediv__(self, other):
138 + return self.apply("div", self, other)
139 +
140 + def __rtruediv__(self, other):
141 + return self.apply("div", other, self)
142 +
143 + def __mod__(self, other):
144 + return self.apply("mod", self, other)
145 +
146 + def __rmod__(self, other):
147 + return self.apply("mod", other, self)
148 +
149 + def __pow__(self, other):
150 + return self.apply("pow", self, other)
151 +
152 + def __rpow__(self, other):
153 + return self.apply("pow", other, self)
154 +
155 + if not py3:
156 + # Provide __div__ and __rdiv__ for pre-Py3k
157 + __div__ = __truediv__
158 + __rdiv__ = __rtruediv__
159 + del __truediv__
160 + del __rtruediv__
161 +
162 + # bitwise
163 + def __invert__(self):
164 + return self.apply("invert", self)
165 +
166 + def __and__(self, other):
167 + return self.apply("and", self, other)
168 +
169 + def __rand__(self, other):
170 + return self.apply("and", other, self)
171 +
172 + def __or__(self, other):
173 + return self.apply("or", self, other)
174 +
175 + def __ror__(self, other):
176 + return self.apply("or", other, self)
177 +
178 + def __xor__(self, other):
179 + return self.apply("xor", self, other)
180 +
181 + def __rxor__(self, other):
182 + return self.apply("xor", other, self)
183 +
184 + def __lshift__(self, other):
185 + return self.apply("lshift", self, other)
186 +
187 + def __rshift__(self, other):
188 + return self.apply("rshift", self, other)
189 +
190 + # logical
191 + def __eq__(self, other):
192 + return self.apply("eq", self, other)
193 +
194 + def __ne__(self, other):
195 + return self.apply("ne", self, other)
196 +
197 + def __lt__(self, other):
198 + return self.apply("lt", self, other)
199 +
200 + def __le__(self, other):
201 + return self.apply("le", self, other)
202 +
203 + def __gt__(self, other):
204 + return self.apply("gt", self, other)
205 +
206 + def __ge__(self, other):
207 + return self.apply("ge", self, other)
208 +
209 +
210 +# conversions
211 +def imagemath_int(self):
212 + return _Operand(self.im.convert("I"))
213 +
214 +
215 +def imagemath_float(self):
216 + return _Operand(self.im.convert("F"))
217 +
218 +
219 +# logical
220 +def imagemath_equal(self, other):
221 + return self.apply("eq", self, other, mode="I")
222 +
223 +
224 +def imagemath_notequal(self, other):
225 + return self.apply("ne", self, other, mode="I")
226 +
227 +
228 +def imagemath_min(self, other):
229 + return self.apply("min", self, other)
230 +
231 +
232 +def imagemath_max(self, other):
233 + return self.apply("max", self, other)
234 +
235 +
236 +def imagemath_convert(self, mode):
237 + return _Operand(self.im.convert(mode))
238 +
239 +
240 +ops = {}
241 +for k, v in list(globals().items()):
242 + if k[:10] == "imagemath_":
243 + ops[k[10:]] = v
244 +
245 +
246 +def eval(expression, _dict={}, **kw):
247 + """
248 + Evaluates an image expression.
249 +
250 + :param expression: A string containing a Python-style expression.
251 + :param options: Values to add to the evaluation context. You
252 + can either use a dictionary, or one or more keyword
253 + arguments.
254 + :return: The evaluated expression. This is usually an image object, but can
255 + also be an integer, a floating point value, or a pixel tuple,
256 + depending on the expression.
257 + """
258 +
259 + # build execution namespace
260 + args = ops.copy()
261 + args.update(_dict)
262 + args.update(kw)
263 + for k, v in list(args.items()):
264 + if hasattr(v, "im"):
265 + args[k] = _Operand(v)
266 +
267 + out = builtins.eval(expression, args)
268 + try:
269 + return out.im
270 + except AttributeError:
271 + return out
1 +#
2 +# The Python Imaging Library.
3 +# $Id$
4 +#
5 +# standard mode descriptors
6 +#
7 +# History:
8 +# 2006-03-20 fl Added
9 +#
10 +# Copyright (c) 2006 by Secret Labs AB.
11 +# Copyright (c) 2006 by Fredrik Lundh.
12 +#
13 +# See the README file for information on usage and redistribution.
14 +#
15 +
16 +# mode descriptor cache
17 +_modes = None
18 +
19 +
20 +class ModeDescriptor(object):
21 + """Wrapper for mode strings."""
22 +
23 + def __init__(self, mode, bands, basemode, basetype):
24 + self.mode = mode
25 + self.bands = bands
26 + self.basemode = basemode
27 + self.basetype = basetype
28 +
29 + def __str__(self):
30 + return self.mode
31 +
32 +
33 +def getmode(mode):
34 + """Gets a mode descriptor for the given mode."""
35 + global _modes
36 + if not _modes:
37 + # initialize mode cache
38 +
39 + from . import Image
40 +
41 + modes = {}
42 + # core modes
43 + for m, (basemode, basetype, bands) in Image._MODEINFO.items():
44 + modes[m] = ModeDescriptor(m, bands, basemode, basetype)
45 + # extra experimental modes
46 + modes["RGBa"] = ModeDescriptor("RGBa", ("R", "G", "B", "a"), "RGB", "L")
47 + modes["LA"] = ModeDescriptor("LA", ("L", "A"), "L", "L")
48 + modes["La"] = ModeDescriptor("La", ("L", "a"), "L", "L")
49 + modes["PA"] = ModeDescriptor("PA", ("P", "A"), "RGB", "L")
50 + # mapping modes
51 + for i16mode in (
52 + "I;16",
53 + "I;16S",
54 + "I;16L",
55 + "I;16LS",
56 + "I;16B",
57 + "I;16BS",
58 + "I;16N",
59 + "I;16NS",
60 + ):
61 + modes[i16mode] = ModeDescriptor(i16mode, ("I",), "L", "L")
62 + # set global mode cache atomically
63 + _modes = modes
64 + return _modes[mode]
1 +# A binary morphology add-on for the Python Imaging Library
2 +#
3 +# History:
4 +# 2014-06-04 Initial version.
5 +#
6 +# Copyright (c) 2014 Dov Grobgeld <dov.grobgeld@gmail.com>
7 +
8 +from __future__ import print_function
9 +
10 +import re
11 +
12 +from . import Image, _imagingmorph
13 +
14 +LUT_SIZE = 1 << 9
15 +
16 +# fmt: off
17 +ROTATION_MATRIX = [
18 + 6, 3, 0,
19 + 7, 4, 1,
20 + 8, 5, 2,
21 +]
22 +MIRROR_MATRIX = [
23 + 2, 1, 0,
24 + 5, 4, 3,
25 + 8, 7, 6,
26 +]
27 +# fmt: on
28 +
29 +
30 +class LutBuilder(object):
31 + """A class for building a MorphLut from a descriptive language
32 +
33 + The input patterns is a list of a strings sequences like these::
34 +
35 + 4:(...
36 + .1.
37 + 111)->1
38 +
39 + (whitespaces including linebreaks are ignored). The option 4
40 + describes a series of symmetry operations (in this case a
41 + 4-rotation), the pattern is described by:
42 +
43 + - . or X - Ignore
44 + - 1 - Pixel is on
45 + - 0 - Pixel is off
46 +
47 + The result of the operation is described after "->" string.
48 +
49 + The default is to return the current pixel value, which is
50 + returned if no other match is found.
51 +
52 + Operations:
53 +
54 + - 4 - 4 way rotation
55 + - N - Negate
56 + - 1 - Dummy op for no other operation (an op must always be given)
57 + - M - Mirroring
58 +
59 + Example::
60 +
61 + lb = LutBuilder(patterns = ["4:(... .1. 111)->1"])
62 + lut = lb.build_lut()
63 +
64 + """
65 +
66 + def __init__(self, patterns=None, op_name=None):
67 + if patterns is not None:
68 + self.patterns = patterns
69 + else:
70 + self.patterns = []
71 + self.lut = None
72 + if op_name is not None:
73 + known_patterns = {
74 + "corner": ["1:(... ... ...)->0", "4:(00. 01. ...)->1"],
75 + "dilation4": ["4:(... .0. .1.)->1"],
76 + "dilation8": ["4:(... .0. .1.)->1", "4:(... .0. ..1)->1"],
77 + "erosion4": ["4:(... .1. .0.)->0"],
78 + "erosion8": ["4:(... .1. .0.)->0", "4:(... .1. ..0)->0"],
79 + "edge": [
80 + "1:(... ... ...)->0",
81 + "4:(.0. .1. ...)->1",
82 + "4:(01. .1. ...)->1",
83 + ],
84 + }
85 + if op_name not in known_patterns:
86 + raise Exception("Unknown pattern " + op_name + "!")
87 +
88 + self.patterns = known_patterns[op_name]
89 +
90 + def add_patterns(self, patterns):
91 + self.patterns += patterns
92 +
93 + def build_default_lut(self):
94 + symbols = [0, 1]
95 + m = 1 << 4 # pos of current pixel
96 + self.lut = bytearray(symbols[(i & m) > 0] for i in range(LUT_SIZE))
97 +
98 + def get_lut(self):
99 + return self.lut
100 +
101 + def _string_permute(self, pattern, permutation):
102 + """string_permute takes a pattern and a permutation and returns the
103 + string permuted according to the permutation list.
104 + """
105 + assert len(permutation) == 9
106 + return "".join(pattern[p] for p in permutation)
107 +
108 + def _pattern_permute(self, basic_pattern, options, basic_result):
109 + """pattern_permute takes a basic pattern and its result and clones
110 + the pattern according to the modifications described in the $options
111 + parameter. It returns a list of all cloned patterns."""
112 + patterns = [(basic_pattern, basic_result)]
113 +
114 + # rotations
115 + if "4" in options:
116 + res = patterns[-1][1]
117 + for i in range(4):
118 + patterns.append(
119 + (self._string_permute(patterns[-1][0], ROTATION_MATRIX), res)
120 + )
121 + # mirror
122 + if "M" in options:
123 + n = len(patterns)
124 + for pattern, res in patterns[0:n]:
125 + patterns.append((self._string_permute(pattern, MIRROR_MATRIX), res))
126 +
127 + # negate
128 + if "N" in options:
129 + n = len(patterns)
130 + for pattern, res in patterns[0:n]:
131 + # Swap 0 and 1
132 + pattern = pattern.replace("0", "Z").replace("1", "0").replace("Z", "1")
133 + res = 1 - int(res)
134 + patterns.append((pattern, res))
135 +
136 + return patterns
137 +
138 + def build_lut(self):
139 + """Compile all patterns into a morphology lut.
140 +
141 + TBD :Build based on (file) morphlut:modify_lut
142 + """
143 + self.build_default_lut()
144 + patterns = []
145 +
146 + # Parse and create symmetries of the patterns strings
147 + for p in self.patterns:
148 + m = re.search(r"(\w*):?\s*\((.+?)\)\s*->\s*(\d)", p.replace("\n", ""))
149 + if not m:
150 + raise Exception('Syntax error in pattern "' + p + '"')
151 + options = m.group(1)
152 + pattern = m.group(2)
153 + result = int(m.group(3))
154 +
155 + # Get rid of spaces
156 + pattern = pattern.replace(" ", "").replace("\n", "")
157 +
158 + patterns += self._pattern_permute(pattern, options, result)
159 +
160 + # compile the patterns into regular expressions for speed
161 + for i, pattern in enumerate(patterns):
162 + p = pattern[0].replace(".", "X").replace("X", "[01]")
163 + p = re.compile(p)
164 + patterns[i] = (p, pattern[1])
165 +
166 + # Step through table and find patterns that match.
167 + # Note that all the patterns are searched. The last one
168 + # caught overrides
169 + for i in range(LUT_SIZE):
170 + # Build the bit pattern
171 + bitpattern = bin(i)[2:]
172 + bitpattern = ("0" * (9 - len(bitpattern)) + bitpattern)[::-1]
173 +
174 + for p, r in patterns:
175 + if p.match(bitpattern):
176 + self.lut[i] = [0, 1][r]
177 +
178 + return self.lut
179 +
180 +
181 +class MorphOp(object):
182 + """A class for binary morphological operators"""
183 +
184 + def __init__(self, lut=None, op_name=None, patterns=None):
185 + """Create a binary morphological operator"""
186 + self.lut = lut
187 + if op_name is not None:
188 + self.lut = LutBuilder(op_name=op_name).build_lut()
189 + elif patterns is not None:
190 + self.lut = LutBuilder(patterns=patterns).build_lut()
191 +
192 + def apply(self, image):
193 + """Run a single morphological operation on an image
194 +
195 + Returns a tuple of the number of changed pixels and the
196 + morphed image"""
197 + if self.lut is None:
198 + raise Exception("No operator loaded")
199 +
200 + if image.mode != "L":
201 + raise Exception("Image must be binary, meaning it must use mode L")
202 + outimage = Image.new(image.mode, image.size, None)
203 + count = _imagingmorph.apply(bytes(self.lut), image.im.id, outimage.im.id)
204 + return count, outimage
205 +
206 + def match(self, image):
207 + """Get a list of coordinates matching the morphological operation on
208 + an image.
209 +
210 + Returns a list of tuples of (x,y) coordinates
211 + of all matching pixels. See :ref:`coordinate-system`."""
212 + if self.lut is None:
213 + raise Exception("No operator loaded")
214 +
215 + if image.mode != "L":
216 + raise Exception("Image must be binary, meaning it must use mode L")
217 + return _imagingmorph.match(bytes(self.lut), image.im.id)
218 +
219 + def get_on_pixels(self, image):
220 + """Get a list of all turned on pixels in a binary image
221 +
222 + Returns a list of tuples of (x,y) coordinates
223 + of all matching pixels. See :ref:`coordinate-system`."""
224 +
225 + if image.mode != "L":
226 + raise Exception("Image must be binary, meaning it must use mode L")
227 + return _imagingmorph.get_on_pixels(image.im.id)
228 +
229 + def load_lut(self, filename):
230 + """Load an operator from an mrl file"""
231 + with open(filename, "rb") as f:
232 + self.lut = bytearray(f.read())
233 +
234 + if len(self.lut) != LUT_SIZE:
235 + self.lut = None
236 + raise Exception("Wrong size operator file!")
237 +
238 + def save_lut(self, filename):
239 + """Save an operator to an mrl file"""
240 + if self.lut is None:
241 + raise Exception("No operator loaded")
242 + with open(filename, "wb") as f:
243 + f.write(self.lut)
244 +
245 + def set_lut(self, lut):
246 + """Set the lut from an external source"""
247 + self.lut = lut
This diff is collapsed. Click to expand it.
1 +#
2 +# The Python Imaging Library.
3 +# $Id$
4 +#
5 +# image palette object
6 +#
7 +# History:
8 +# 1996-03-11 fl Rewritten.
9 +# 1997-01-03 fl Up and running.
10 +# 1997-08-23 fl Added load hack
11 +# 2001-04-16 fl Fixed randint shadow bug in random()
12 +#
13 +# Copyright (c) 1997-2001 by Secret Labs AB
14 +# Copyright (c) 1996-1997 by Fredrik Lundh
15 +#
16 +# See the README file for information on usage and redistribution.
17 +#
18 +
19 +import array
20 +
21 +from . import GimpGradientFile, GimpPaletteFile, ImageColor, PaletteFile
22 +
23 +
24 +class ImagePalette(object):
25 + """
26 + Color palette for palette mapped images
27 +
28 + :param mode: The mode to use for the Palette. See:
29 + :ref:`concept-modes`. Defaults to "RGB"
30 + :param palette: An optional palette. If given, it must be a bytearray,
31 + an array or a list of ints between 0-255 and of length ``size``
32 + times the number of colors in ``mode``. The list must be aligned
33 + by channel (All R values must be contiguous in the list before G
34 + and B values.) Defaults to 0 through 255 per channel.
35 + :param size: An optional palette size. If given, it cannot be equal to
36 + or greater than 256. Defaults to 0.
37 + """
38 +
39 + def __init__(self, mode="RGB", palette=None, size=0):
40 + self.mode = mode
41 + self.rawmode = None # if set, palette contains raw data
42 + self.palette = palette or bytearray(range(256)) * len(self.mode)
43 + self.colors = {}
44 + self.dirty = None
45 + if (size == 0 and len(self.mode) * 256 != len(self.palette)) or (
46 + size != 0 and size != len(self.palette)
47 + ):
48 + raise ValueError("wrong palette size")
49 +
50 + def copy(self):
51 + new = ImagePalette()
52 +
53 + new.mode = self.mode
54 + new.rawmode = self.rawmode
55 + if self.palette is not None:
56 + new.palette = self.palette[:]
57 + new.colors = self.colors.copy()
58 + new.dirty = self.dirty
59 +
60 + return new
61 +
62 + def getdata(self):
63 + """
64 + Get palette contents in format suitable for the low-level
65 + ``im.putpalette`` primitive.
66 +
67 + .. warning:: This method is experimental.
68 + """
69 + if self.rawmode:
70 + return self.rawmode, self.palette
71 + return self.mode + ";L", self.tobytes()
72 +
73 + def tobytes(self):
74 + """Convert palette to bytes.
75 +
76 + .. warning:: This method is experimental.
77 + """
78 + if self.rawmode:
79 + raise ValueError("palette contains raw palette data")
80 + if isinstance(self.palette, bytes):
81 + return self.palette
82 + arr = array.array("B", self.palette)
83 + if hasattr(arr, "tobytes"):
84 + return arr.tobytes()
85 + return arr.tostring()
86 +
87 + # Declare tostring as an alias for tobytes
88 + tostring = tobytes
89 +
90 + def getcolor(self, color):
91 + """Given an rgb tuple, allocate palette entry.
92 +
93 + .. warning:: This method is experimental.
94 + """
95 + if self.rawmode:
96 + raise ValueError("palette contains raw palette data")
97 + if isinstance(color, tuple):
98 + try:
99 + return self.colors[color]
100 + except KeyError:
101 + # allocate new color slot
102 + if isinstance(self.palette, bytes):
103 + self.palette = bytearray(self.palette)
104 + index = len(self.colors)
105 + if index >= 256:
106 + raise ValueError("cannot allocate more than 256 colors")
107 + self.colors[color] = index
108 + self.palette[index] = color[0]
109 + self.palette[index + 256] = color[1]
110 + self.palette[index + 512] = color[2]
111 + self.dirty = 1
112 + return index
113 + else:
114 + raise ValueError("unknown color specifier: %r" % color)
115 +
116 + def save(self, fp):
117 + """Save palette to text file.
118 +
119 + .. warning:: This method is experimental.
120 + """
121 + if self.rawmode:
122 + raise ValueError("palette contains raw palette data")
123 + if isinstance(fp, str):
124 + fp = open(fp, "w")
125 + fp.write("# Palette\n")
126 + fp.write("# Mode: %s\n" % self.mode)
127 + for i in range(256):
128 + fp.write("%d" % i)
129 + for j in range(i * len(self.mode), (i + 1) * len(self.mode)):
130 + try:
131 + fp.write(" %d" % self.palette[j])
132 + except IndexError:
133 + fp.write(" 0")
134 + fp.write("\n")
135 + fp.close()
136 +
137 +
138 +# --------------------------------------------------------------------
139 +# Internal
140 +
141 +
142 +def raw(rawmode, data):
143 + palette = ImagePalette()
144 + palette.rawmode = rawmode
145 + palette.palette = data
146 + palette.dirty = 1
147 + return palette
148 +
149 +
150 +# --------------------------------------------------------------------
151 +# Factories
152 +
153 +
154 +def make_linear_lut(black, white):
155 + lut = []
156 + if black == 0:
157 + for i in range(256):
158 + lut.append(white * i // 255)
159 + else:
160 + raise NotImplementedError # FIXME
161 + return lut
162 +
163 +
164 +def make_gamma_lut(exp):
165 + lut = []
166 + for i in range(256):
167 + lut.append(int(((i / 255.0) ** exp) * 255.0 + 0.5))
168 + return lut
169 +
170 +
171 +def negative(mode="RGB"):
172 + palette = list(range(256))
173 + palette.reverse()
174 + return ImagePalette(mode, palette * len(mode))
175 +
176 +
177 +def random(mode="RGB"):
178 + from random import randint
179 +
180 + palette = []
181 + for i in range(256 * len(mode)):
182 + palette.append(randint(0, 255))
183 + return ImagePalette(mode, palette)
184 +
185 +
186 +def sepia(white="#fff0c0"):
187 + r, g, b = ImageColor.getrgb(white)
188 + r = make_linear_lut(0, r)
189 + g = make_linear_lut(0, g)
190 + b = make_linear_lut(0, b)
191 + return ImagePalette("RGB", r + g + b)
192 +
193 +
194 +def wedge(mode="RGB"):
195 + return ImagePalette(mode, list(range(256)) * len(mode))
196 +
197 +
198 +def load(filename):
199 +
200 + # FIXME: supports GIMP gradients only
201 +
202 + with open(filename, "rb") as fp:
203 +
204 + for paletteHandler in [
205 + GimpPaletteFile.GimpPaletteFile,
206 + GimpGradientFile.GimpGradientFile,
207 + PaletteFile.PaletteFile,
208 + ]:
209 + try:
210 + fp.seek(0)
211 + lut = paletteHandler(fp).getpalette()
212 + if lut:
213 + break
214 + except (SyntaxError, ValueError):
215 + # import traceback
216 + # traceback.print_exc()
217 + pass
218 + else:
219 + raise IOError("cannot load palette")
220 +
221 + return lut # data, rawmode
1 +#
2 +# The Python Imaging Library
3 +# $Id$
4 +#
5 +# path interface
6 +#
7 +# History:
8 +# 1996-11-04 fl Created
9 +# 2002-04-14 fl Added documentation stub class
10 +#
11 +# Copyright (c) Secret Labs AB 1997.
12 +# Copyright (c) Fredrik Lundh 1996.
13 +#
14 +# See the README file for information on usage and redistribution.
15 +#
16 +
17 +from . import Image
18 +
19 +Path = Image.core.path
1 +#
2 +# The Python Imaging Library.
3 +# $Id$
4 +#
5 +# a simple Qt image interface.
6 +#
7 +# history:
8 +# 2006-06-03 fl: created
9 +# 2006-06-04 fl: inherit from QImage instead of wrapping it
10 +# 2006-06-05 fl: removed toimage helper; move string support to ImageQt
11 +# 2013-11-13 fl: add support for Qt5 (aurelien.ballier@cyclonit.com)
12 +#
13 +# Copyright (c) 2006 by Secret Labs AB
14 +# Copyright (c) 2006 by Fredrik Lundh
15 +#
16 +# See the README file for information on usage and redistribution.
17 +#
18 +
19 +import sys
20 +import warnings
21 +from io import BytesIO
22 +
23 +from . import Image
24 +from ._util import isPath, py3
25 +
26 +qt_versions = [["5", "PyQt5"], ["side2", "PySide2"], ["4", "PyQt4"], ["side", "PySide"]]
27 +
28 +WARNING_TEXT = (
29 + "Support for EOL {} is deprecated and will be removed in a future version. "
30 + "Please upgrade to PyQt5 or PySide2."
31 +)
32 +
33 +# If a version has already been imported, attempt it first
34 +qt_versions.sort(key=lambda qt_version: qt_version[1] in sys.modules, reverse=True)
35 +for qt_version, qt_module in qt_versions:
36 + try:
37 + if qt_module == "PyQt5":
38 + from PyQt5.QtGui import QImage, qRgba, QPixmap
39 + from PyQt5.QtCore import QBuffer, QIODevice
40 + elif qt_module == "PySide2":
41 + from PySide2.QtGui import QImage, qRgba, QPixmap
42 + from PySide2.QtCore import QBuffer, QIODevice
43 + elif qt_module == "PyQt4":
44 + from PyQt4.QtGui import QImage, qRgba, QPixmap
45 + from PyQt4.QtCore import QBuffer, QIODevice
46 +
47 + warnings.warn(WARNING_TEXT.format(qt_module), DeprecationWarning)
48 + elif qt_module == "PySide":
49 + from PySide.QtGui import QImage, qRgba, QPixmap
50 + from PySide.QtCore import QBuffer, QIODevice
51 +
52 + warnings.warn(WARNING_TEXT.format(qt_module), DeprecationWarning)
53 + except (ImportError, RuntimeError):
54 + continue
55 + qt_is_installed = True
56 + break
57 +else:
58 + qt_is_installed = False
59 + qt_version = None
60 +
61 +
62 +def rgb(r, g, b, a=255):
63 + """(Internal) Turns an RGB color into a Qt compatible color integer."""
64 + # use qRgb to pack the colors, and then turn the resulting long
65 + # into a negative integer with the same bitpattern.
66 + return qRgba(r, g, b, a) & 0xFFFFFFFF
67 +
68 +
69 +def fromqimage(im):
70 + """
71 + :param im: A PIL Image object, or a file name
72 + (given either as Python string or a PyQt string object)
73 + """
74 + buffer = QBuffer()
75 + buffer.open(QIODevice.ReadWrite)
76 + # preserve alpha channel with png
77 + # otherwise ppm is more friendly with Image.open
78 + if im.hasAlphaChannel():
79 + im.save(buffer, "png")
80 + else:
81 + im.save(buffer, "ppm")
82 +
83 + b = BytesIO()
84 + try:
85 + b.write(buffer.data())
86 + except TypeError:
87 + # workaround for Python 2
88 + b.write(str(buffer.data()))
89 + buffer.close()
90 + b.seek(0)
91 +
92 + return Image.open(b)
93 +
94 +
95 +def fromqpixmap(im):
96 + return fromqimage(im)
97 + # buffer = QBuffer()
98 + # buffer.open(QIODevice.ReadWrite)
99 + # # im.save(buffer)
100 + # # What if png doesn't support some image features like animation?
101 + # im.save(buffer, 'ppm')
102 + # bytes_io = BytesIO()
103 + # bytes_io.write(buffer.data())
104 + # buffer.close()
105 + # bytes_io.seek(0)
106 + # return Image.open(bytes_io)
107 +
108 +
109 +def align8to32(bytes, width, mode):
110 + """
111 + converts each scanline of data from 8 bit to 32 bit aligned
112 + """
113 +
114 + bits_per_pixel = {"1": 1, "L": 8, "P": 8}[mode]
115 +
116 + # calculate bytes per line and the extra padding if needed
117 + bits_per_line = bits_per_pixel * width
118 + full_bytes_per_line, remaining_bits_per_line = divmod(bits_per_line, 8)
119 + bytes_per_line = full_bytes_per_line + (1 if remaining_bits_per_line else 0)
120 +
121 + extra_padding = -bytes_per_line % 4
122 +
123 + # already 32 bit aligned by luck
124 + if not extra_padding:
125 + return bytes
126 +
127 + new_data = []
128 + for i in range(len(bytes) // bytes_per_line):
129 + new_data.append(
130 + bytes[i * bytes_per_line : (i + 1) * bytes_per_line]
131 + + b"\x00" * extra_padding
132 + )
133 +
134 + return b"".join(new_data)
135 +
136 +
137 +def _toqclass_helper(im):
138 + data = None
139 + colortable = None
140 +
141 + # handle filename, if given instead of image name
142 + if hasattr(im, "toUtf8"):
143 + # FIXME - is this really the best way to do this?
144 + if py3:
145 + im = str(im.toUtf8(), "utf-8")
146 + else:
147 + im = unicode(im.toUtf8(), "utf-8") # noqa: F821
148 + if isPath(im):
149 + im = Image.open(im)
150 +
151 + if im.mode == "1":
152 + format = QImage.Format_Mono
153 + elif im.mode == "L":
154 + format = QImage.Format_Indexed8
155 + colortable = []
156 + for i in range(256):
157 + colortable.append(rgb(i, i, i))
158 + elif im.mode == "P":
159 + format = QImage.Format_Indexed8
160 + colortable = []
161 + palette = im.getpalette()
162 + for i in range(0, len(palette), 3):
163 + colortable.append(rgb(*palette[i : i + 3]))
164 + elif im.mode == "RGB":
165 + data = im.tobytes("raw", "BGRX")
166 + format = QImage.Format_RGB32
167 + elif im.mode == "RGBA":
168 + try:
169 + data = im.tobytes("raw", "BGRA")
170 + except SystemError:
171 + # workaround for earlier versions
172 + r, g, b, a = im.split()
173 + im = Image.merge("RGBA", (b, g, r, a))
174 + format = QImage.Format_ARGB32
175 + else:
176 + raise ValueError("unsupported image mode %r" % im.mode)
177 +
178 + __data = data or align8to32(im.tobytes(), im.size[0], im.mode)
179 + return {"data": __data, "im": im, "format": format, "colortable": colortable}
180 +
181 +
182 +if qt_is_installed:
183 +
184 + class ImageQt(QImage):
185 + def __init__(self, im):
186 + """
187 + An PIL image wrapper for Qt. This is a subclass of PyQt's QImage
188 + class.
189 +
190 + :param im: A PIL Image object, or a file name (given either as
191 + Python string or a PyQt string object).
192 + """
193 + im_data = _toqclass_helper(im)
194 + # must keep a reference, or Qt will crash!
195 + # All QImage constructors that take data operate on an existing
196 + # buffer, so this buffer has to hang on for the life of the image.
197 + # Fixes https://github.com/python-pillow/Pillow/issues/1370
198 + self.__data = im_data["data"]
199 + QImage.__init__(
200 + self,
201 + self.__data,
202 + im_data["im"].size[0],
203 + im_data["im"].size[1],
204 + im_data["format"],
205 + )
206 + if im_data["colortable"]:
207 + self.setColorTable(im_data["colortable"])
208 +
209 +
210 +def toqimage(im):
211 + return ImageQt(im)
212 +
213 +
214 +def toqpixmap(im):
215 + # # This doesn't work. For now using a dumb approach.
216 + # im_data = _toqclass_helper(im)
217 + # result = QPixmap(im_data['im'].size[0], im_data['im'].size[1])
218 + # result.loadFromData(im_data['data'])
219 + # Fix some strange bug that causes
220 + if im.mode == "RGB":
221 + im = im.convert("RGBA")
222 +
223 + qimage = toqimage(im)
224 + return QPixmap.fromImage(qimage)
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff could not be displayed because it is too large.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff could not be displayed because it is too large.
This diff could not be displayed because it is too large.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff could not be displayed because it is too large.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.