python-aalib-0.4/0000755000000000000000000000000014015753105013743 5ustar00rootroot00000000000000python-aalib-0.4/MANIFEST.in0000644000000000000000000000023414015003472015473 0ustar00rootroot00000000000000include MANIFEST.in include LICENSE include doc/LICENSE include doc/changelog include test/*.c include test/*.jpeg include test/*.py include test/Makefile python-aalib-0.4/PKG-INFO0000644000000000000000000000130514015753105015037 0ustar00rootroot00000000000000Metadata-Version: 1.1 Name: python-aalib Version: 0.4 Summary: interface to AAlib Home-page: http://jwilk.net/software/python-aalib Author: Jakub Wilk Author-email: jwilk@jwilk.net License: MIT Description: *python-aalib* is an interface to `AAlib `_, an ASCII art library. Platform: UNKNOWN Classifier: Development Status :: 4 - Beta Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: MIT License Classifier: Operating System :: POSIX Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 2 Classifier: Programming Language :: Python :: 3 Classifier: Topic :: Multimedia :: Graphics python-aalib-0.4/aalib.py0000644000000000000000000002127214015750560015373 0ustar00rootroot00000000000000# encoding=UTF-8 # Copyright © 2009-2021 Jakub Wilk # SPDX-License-Identifier: MIT ''' interface to AAlib, an ASCII art library ''' import ctypes import sys type(b'') # Python >= 2.6 is required if sys.version_info < (3,): import __builtin__ as builtins # pylint: disable=import-error range = builtins.xrange # pylint: disable=redefined-builtin libaa = ctypes.CDLL('libaa.so.1') class Font(ctypes.Structure): pass FontPtr = ctypes.POINTER(Font) class Structure(ctypes.Structure): def clone(self): clone = type(self)() ctypes.pointer(clone)[0] = self return clone class HardwareSettings(Structure): _fields_ = [ ('font', FontPtr), ('options', ctypes.c_int), ('min_width', ctypes.c_int), ('min_height', ctypes.c_int), ('max_width', ctypes.c_int), ('max_height', ctypes.c_int), ('recommended_width', ctypes.c_int), ('recommended_height', ctypes.c_int), ('physical_width', ctypes.c_int), ('physical_height', ctypes.c_int), ('width', ctypes.c_int), ('height', ctypes.c_int), ('dim_value', ctypes.c_double), ('bold_value', ctypes.c_double), ] HardwareSettingsPtr = ctypes.POINTER(HardwareSettings) OPTION_NORMAL_MASK = 1 OPTION_DIM_MASK = 2 OPTION_BRIGHT_MASK = 4 OPTION_BOLD_MASK = 8 OPTION_REVERSE_MASK = 16 OPTION_ALL_MASKS = 128 OPTION_8BITS = 256 ATTRIBUTE_NORMAL = 0 ATTRIBUTE_DIM = 1 ATTRIBUTE_BRIGHT = 2 ATTRIBUTE_BOLD = 3 ATTRIBUTE_REVERSE = 4 DEFAULT_HARDWARE_SETTINGS = HardwareSettings.in_dll(libaa, 'aa_defparams') class RenderSettings(Structure): _fields_ = [ ('brightness', ctypes.c_int), ('contrast', ctypes.c_int), ('gamma', ctypes.c_float), ('dithering_mode', ctypes.c_int), ('inversion', ctypes.c_int), ('random', ctypes.c_int), ] RenderSettingsPtr = ctypes.POINTER(RenderSettings) DEFAULT_RENDER_SETTINGS = RenderSettings.in_dll(libaa, 'aa_defrenderparams') DITHER_NONE = 0 DITHER_ERROR_DISTRIBUTION = 1 DITHER_FLOYD_STEINBERG = 2 class Driver(Structure): pass DriverPtr = ctypes.POINTER(Driver) class Context(Structure): pass ContextPtr = ctypes.POINTER(Context) aa_init = libaa.aa_init aa_init.argtypes = [DriverPtr, HardwareSettingsPtr, ctypes.c_void_p] aa_init.restype = ContextPtr aa_close = libaa.aa_close aa_close.argtypes = [ContextPtr] aa_image = libaa.aa_image aa_image.argtypes = [ContextPtr] aa_image.restype = ctypes.POINTER(ctypes.c_ubyte) aa_text = libaa.aa_text aa_text.argtypes = [ContextPtr] aa_text.restype = ctypes.POINTER(ctypes.c_ubyte) aa_attrs = libaa.aa_attrs aa_attrs.argtypes = [ContextPtr] aa_attrs.restype = ctypes.POINTER(ctypes.c_ubyte) aa_imgwidth = libaa.aa_imgwidth aa_imgwidth.argtypes = [ContextPtr] aa_imgwidth.restype = ctypes.c_int aa_imgheight = libaa.aa_imgheight aa_imgheight.argtypes = [ContextPtr] aa_imgheight.restype = ctypes.c_int aa_scrwidth = libaa.aa_scrwidth aa_scrwidth.argtypes = [ContextPtr] aa_scrwidth.restype = ctypes.c_int aa_scrheight = libaa.aa_scrheight aa_scrheight.argtypes = [ContextPtr] aa_scrheight.restype = ctypes.c_int aa_render = libaa.aa_render aa_render.argtypes = [ContextPtr, RenderSettingsPtr] + 4 * [ctypes.c_int] aa_mem_d = Driver.in_dll(libaa, 'mem_d') class ScreenInitializationFailed(Exception): pass class NoImageBuffer(Exception): pass class Screen(object): def _get_default_settings(self): return DEFAULT_HARDWARE_SETTINGS.clone() def __init__(self, **kwargs): '''Initialize the virtual screen. Possible keyword arguments: - `font`, - `options`, - `min_width`, `min_height` (in pixels), - `max_width`, `max_height` (in pixels), - `recommended_width`, `recommended_height` (in pixels), - `width`, `height` (in pixels), - `physical_width`, `physical_height` (in mm), - `dim_value`, - `bold_value`. ''' settings = self._get_default_settings() for k, v in kwargs.items(): setattr(settings, k, v) context = self._context = aa_init(ctypes.pointer(aa_mem_d), ctypes.pointer(settings), None) if context is None: raise ScreenInitializationFailed self._render_width = aa_scrwidth(context) self._render_height = aa_scrheight(context) self._virtual_width = aa_imgwidth(context) self._virtual_height = aa_imgheight(context) self._framebuffer = aa_image(context) def close(self): try: context = self._context except AttributeError: return aa_close(context) del self._context @property def render_width(self): '''Width of rendered image, in pixels.''' return self._render_width @property def render_height(self): '''Height of rendered image, in pixels.''' return self._render_height @property def render_size(self): '''Size of rendered image, in pixels.''' return self._render_width, self._render_height @property def virtual_width(self): '''Height of the virtual screen, in pixels.''' return self._virtual_width @property def virtual_height(self): '''Height of the virtual screen, in pixels.''' return self._virtual_height @property def virtual_size(self): '''Size of the virtual screen, in pixels.''' return self._virtual_width, self._virtual_height def __setitem__(self, xy, value): '''Put a pixel on the virtual screen.''' (x, y) = xy self._framebuffer[y * self._virtual_width + x] = value def put_image(self, xy, image): virtual_width = self._virtual_width virtual_height = self._virtual_height (x0, y0) = xy (image_width, image_height) = image.size for y in range(max(y0, 0), min(y0 + image_height, virtual_height)): p = y * virtual_width for x in range(max(x0, 0), min(x0 + image_width, virtual_width)): self._framebuffer[p + x] = image.getpixel((x - x0, y - y0)) def __getitem__(self, xy): '''Get a pixel from the virtual screen.''' (x, y) = xy return self._framebuffer[y * self._virtual_width + x] def render(self, **kwargs): '''Render the image. Possible keyword arguments: - `brightness`, - `contrast`, - `gamma`, - `dithering_mode` (see `DITHER_*` constants), - `inversion`, - `random`. ''' settings = DEFAULT_RENDER_SETTINGS.clone() for k, v in kwargs.items(): setattr(settings, k, v) context = self._context buffer = aa_image(context) if buffer is None: raise NoImageBuffer width, height = self._render_width, self._render_height aa_render(context, settings, 0, 0, width, height) text = aa_text(context) attrs = aa_attrs(context) return [ [ (chr(text[y * width + x]), attrs[y * width + x]) for x in range(width) ] for y in range(height) ] def __del__(self): self.close() class AsciiScreen(Screen): '''Pure ASCII screen.''' _formats = {ATTRIBUTE_NORMAL: '{s}'} def _get_default_settings(self): settings = Screen._get_default_settings(self) settings.options = OPTION_NORMAL_MASK return settings def render(self, **kwargs): raw = Screen.render(self, **kwargs) return '\n'.join( ''.join(self._formats[attr].format(s=ch) for (ch, attr) in line) for line in raw ) render.__doc__ = Screen.render.__doc__ class AnsiScreen(AsciiScreen): '''Screen that uses ANSI escape sequences.''' _formats = { ATTRIBUTE_NORMAL: '{s}', ATTRIBUTE_BRIGHT: '\x1B[1m{s}\x1B[0m', } def _get_default_settings(self): settings = Screen._get_default_settings(self) settings.options = OPTION_NORMAL_MASK | OPTION_BRIGHT_MASK return settings class LinuxScreen(AsciiScreen): '''Screen that uses Linux console escape sequences.''' _formats = { ATTRIBUTE_NORMAL: '{s}', ATTRIBUTE_BOLD: '\x1B[1m{s}\x1B[0m', ATTRIBUTE_DIM: '\x1B[30;1m{s}\x1B[0m', ATTRIBUTE_REVERSE: '\x1B[7m{s}\x1B[0m', } def _get_default_settings(self): settings = Screen._get_default_settings(self) settings.options = OPTION_NORMAL_MASK | OPTION_BOLD_MASK | OPTION_DIM_MASK | OPTION_REVERSE_MASK return settings __all__ = ( 'AsciiScreen', 'AnsiScreen', 'LinuxScreen', 'ScreenInitializationFailed', 'DITHER_NONE', 'DITHER_ERROR_DISTRIBUTION', 'DITHER_FLOYD_STEINBERG', ) # vim:ts=4 sts=4 sw=4 et python-aalib-0.4/doc/0000755000000000000000000000000014015753105014510 5ustar00rootroot00000000000000python-aalib-0.4/doc/LICENSE0000644000000000000000000000207414015750557015530 0ustar00rootroot00000000000000Copyright © 2009-2021 Jakub Wilk Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. python-aalib-0.4/doc/changelog0000644000000000000000000000330314015751075016365 0ustar00rootroot00000000000000python-aalib (0.4) unstable; urgency=low * Use default structure field alignment. This fixes ABI mismatch on 64-bit architectures. https://github.com/jwilk/python-aalib/issues/4 * Add ABI checking tests. * Add separate license file. * Stop using to 2to3. * Include MANIFEST.in in the source tarball. * Use distutils644 to normalize source tarball permissions etc. -- Jakub Wilk Thu, 25 Feb 2021 17:37:15 +0100 python-aalib (0.3.2) unstable; urgency=low * Include test image in the tarball. Thanks to Stefano Rivera for the bug report. https://github.com/jwilk/python-aalib/issues/1 -- Jakub Wilk Sun, 12 Jun 2016 00:15:04 +0200 python-aalib (0.3.1) unstable; urgency=low * Drop support for Python 2.5. * Make the test work offline. -- Jakub Wilk Sat, 28 May 2016 15:00:31 +0200 python-aalib (0.3) unstable; urgency=low * Add support for Python 3.X. * Update the package descriptions. -- Jakub Wilk Sat, 02 Mar 2013 19:31:06 +0100 python-aalib (0.2.1) unstable; urgency=low * Tests: fix compatibility with PIL ≥ 1.2. -- Jakub Wilk Mon, 11 Feb 2013 16:16:06 +0100 python-aalib (0.2) unstable; urgency=low * Optimize Screen.put_image(). * Relicense to the Expat license. -- Jakub Wilk Thu, 11 Nov 2010 23:55:24 +0100 python-aalib (0.1.1) unstable; urgency=low * Define the NoImageBuffer exception. Thanks to Piotr Ożarowski for the bug report. -- Jakub Wilk Sun, 24 Jan 2010 23:27:02 +0100 python-aalib (0.1) unstable; urgency=low * Initial release. -- Jakub Wilk Sun, 22 Feb 2009 18:51:00 +0100 python-aalib-0.4/setup.py0000644000000000000000000000343114015750560015460 0ustar00rootroot00000000000000# encoding=UTF-8 # Copyright © 2009-2019 Jakub Wilk # SPDX-License-Identifier: MIT ''' *python-aalib* is an interface to `AAlib `_, an ASCII art library. ''' import io import os import distutils.core import distutils.command.build_py from distutils.command.sdist import sdist as distutils_sdist try: import distutils644 except ImportError: pass else: distutils644.install() type(b'') # Python >= 2.6 is required classifiers = ''' Development Status :: 4 - Beta Intended Audience :: Developers License :: OSI Approved :: MIT License Operating System :: POSIX Programming Language :: Python Programming Language :: Python :: 2 Programming Language :: Python :: 3 Topic :: Multimedia :: Graphics '''.strip().splitlines() def get_version(): path = os.path.join('doc/changelog') with io.open(path, encoding='UTF-8') as file: line = file.readline() return line.split()[1].strip('()') class cmd_sdist(distutils_sdist): def maybe_move_file(self, base_dir, src, dst): src = os.path.join(base_dir, src) dst = os.path.join(base_dir, dst) if os.path.exists(src): self.move_file(src, dst) def make_release_tree(self, base_dir, files): distutils_sdist.make_release_tree(self, base_dir, files) self.maybe_move_file(base_dir, 'LICENSE', 'doc/LICENSE') distutils.core.setup( name='python-aalib', version=get_version(), license='MIT', description='interface to AAlib', long_description=__doc__.strip(), classifiers=classifiers, url='http://jwilk.net/software/python-aalib', author='Jakub Wilk', author_email='jwilk@jwilk.net', py_modules=['aalib'], cmdclass=dict( sdist=cmd_sdist, ), ) # vim:ts=4 sts=4 sw=4 et python-aalib-0.4/test/0000755000000000000000000000000014015753105014722 5ustar00rootroot00000000000000python-aalib-0.4/test/Makefile0000644000000000000000000000064114015007752016363 0ustar00rootroot00000000000000# Copyright © 2021 Jakub Wilk # SPDX-License-Identifier: MIT PYTHON = python CFLAGS ?= -O2 -g CFLAGS += -Wall .PHONY: all all: smoke-test .PHONY: smoke-test smoke-test: $(PYTHON) test.py .PHONY: abi-test abi-test: dump-abi ./dump-abi > abi.c.txt $(PYTHON) dump-abi.py > abi.py.txt diff -U999 abi.c.txt abi.py.txt .PHONY: clean clean: rm -f dump-abi abi.*.txt # vim:ts=4 sts=4 sw=4 noet python-aalib-0.4/test/dump-abi.c0000644000000000000000000000177114015002466016567 0ustar00rootroot00000000000000/* Copyright © 2021 Jakub Wilk * SPDX-License-Identifier: MIT */ #include #include #include #define PRINT_SIZE() do { \ printf("=%zu\n", sizeof(struct STRUCT)); \ } while (0) #define PRINT_OFS(fld) do { \ printf("%zu\n", offsetof(struct STRUCT, fld)); \ } while (0) int main(int argc, char **argv) { #define STRUCT aa_hardware_params PRINT_OFS(font); PRINT_OFS(supported); PRINT_OFS(minwidth); PRINT_OFS(minheight); PRINT_OFS(maxwidth); PRINT_OFS(maxheight); PRINT_OFS(recwidth); PRINT_OFS(recheight); PRINT_OFS(mmwidth); PRINT_OFS(mmheight); PRINT_OFS(width); PRINT_OFS(height); PRINT_OFS(dimmul); PRINT_OFS(boldmul); PRINT_SIZE(); #undef STRUCT #define STRUCT aa_renderparams PRINT_OFS(bright); PRINT_OFS(contrast); PRINT_OFS(gamma); PRINT_OFS(dither); PRINT_OFS(inversion); PRINT_OFS(randomval); PRINT_SIZE(); return 0; } /* vim:set ts=4 sts=4 sw=4 et: */ python-aalib-0.4/test/dump-abi.py0000644000000000000000000000100614015750562016773 0ustar00rootroot00000000000000# encoding=UTF-8 # Copyright © 2021 Jakub Wilk # SPDX-License-Identifier: MIT from __future__ import print_function import ctypes import aalib type(b'') # Python >= 2.6 is required def main(): for struct in aalib.HardwareSettings, aalib.RenderSettings: for fldname, _ in struct._fields_: field = getattr(struct, fldname) print(field.offset) print('=', ctypes.sizeof(struct), sep='') if __name__ == '__main__': main() # vim:ts=4 sts=4 sw=4 et python-aalib-0.4/test/python.jpeg0000644000000000000000000002320212722277170017117 0ustar00rootroot00000000000000JFIFHHC   %# , #&')*)-0-(0%()(C   ((((((((((((((((((((((((((((((((((((((((((((((((((( |+suo geDoug孄;x][?If:utR]\9TnEe+>v*^ƹ{!}S+y3{͜u=ykI,0w}x6*' ;SQ|BY;gzƧq)Irޛ忆yfRWcg3:Zݭ[n|jkgX1?I^[;ifeͱ-o}NL݀;uEkupi s6;æ+5u6g/Nu[-o`tK >5t7$tc{-{1V{_sfT]^`KYmf>y߿ղ=e9iW63W-mwcw=rΚ,ڵ:ng=NذΡ1ҳ;Mιq>l8b!w?dyK}G˧AĹ>>ze>'kY2Yy'imm[_<.T9cy-pk7ݳZ;>sŵ5o ,yR.H]ZNk2?h*@ !0"#$AP`6- j9z+ ˽n+qߔЭjm<"ŹMGƆٳk9vЩm$l|_ uITPJKa]`*R)v/ɥ=o,U=!E'I.㱳-&Ksb Jq+j^mk5͖Vcd5K,k?9cbNx$NJg. lv kU?% !@01Q"AP`?<$R{i]6=g)b$""8(DetkLM$B HANq8.n лy Z?LlZ6ֹqfLBp ! ޗP$!됞I:OO(7{ӑZdz(58" i/:tŌ27uxG/[<ǗJS+ Tɣs>%MW3 Txabl$bX^ķJ%N($di3?7K "jhT4Mr5I!dNU|bUEҠ7vڛ%puE6hc59{k?D]M(˖>z3ܷ)>93_1aB\^!d`tA]Q\9Y ˧: EX6i;1THNv2K˅í9V)0@? k"[|-ke=ٗ5F@;*Z40Lٮk4(t{> [S Tʍ kB[S =r{xb4Do&Ub=*@#徆zkzk{kddmjumKǾd:G7&V;5Ux 3A(uh?j~&9&OoW4}NL.=8ʙm|(ֽeٜI"Hb׵Fc1Zj⮤6͵gʟYM%G,kX#oVu2\BoVIq-$hnEycSZZIf̢O}rS!LjV򃧢F0j1^bM-8dW[;.ƽ*,Yb|<)d*#}42tԠנ,&6 ԇg"O޵2?.YdѶsGWF55֥[T|OJ֥P1Jjڴ<3E\e]C!Dƿ@Y|j.&k߾ŝ:; 1-:$ p]my/)O>+) v-4Ĺc/ jԬݯ4~q{jen$kҭđ^axO(t6hk|!/ mtf=A^ތkeaz5ڂ}!fA=zɆRrݲoeK^RM͇Jic4L_CzfI}Nrg|JB+bTv5ՎC5N{ͱ5nY-޴|v^k1W]m[":Uygˆeԧf4|D}/d #m6kԞH<ڬXjYpk)6d:HN8Crܟڝ$=JGC˧1432Q~ހS<8ɭJMYEuXC0hoWrigpo4J[]i vڔjY[ (=N*!1AQaq @0P?!P-h"rʥ| ^MAsъ[1ZYy/ZXM%~?t̬sQmVTZY.&|_iNU7|DUXhwW8eme;'>-!хUuzIo6E!f5Z*>?twZW_=)4wC_\'sL@U<|mgPVunvy#˰&ytk5VrIyipQڷ<,-J6Ϝb_ 7\xWm,&f6^fY}QNbcgvLUeF%MNDzY5VE?y7uݯmK/myij҈6}/|C.hF_Y߮5ib7}uBP2DZ޻A2ϮJ@+cC oؾ_; n-i%ᝋAl^#<3tL-Ũxɀ^!}DDS5k̇sk˿~}`Mȫϯ^# \DN'tRn!Yiyeu4]`zSsrE5sv, < {˧(a”R=o~g%5pӜ.`p0Q[anp/2rrW,h R0ƽ`K+)۬wE6ҟEʁEEBx}3uۚ(!o!jN^P_;g}?$|;I@_h4348>@=̕v8o@̲BvbYYBKW\)*1>[ys|PzKP5Μ%r}W];%cҒxLa^+JC'ՒDf2V>1TGɘ5l ?J5:pAf`&Y,MW3_0>HS`e^Kbo-Rߏ16Sܣܐ}`6lU`j tx4Ytuަ=%*Z:ͤø*z%n՗==b׹Hhޮ=Uf_WD\C-1֮/i V/2qQp#o8(#wJ90; us/HdU&H1 Ze5YZ] <HRxl;̊8jR^)A<LfC8x}ɨAp9al玚7[r;as ~%]X͠Txd4,o`)_o~jj;JSNFG(PBؙxt\3OBc4kSmahS Tjc~wY#㟉xj:{7 ؅ܭ +8Eשׂ(]NNXrzd*R-!*b+ nM't I$I$I$I$I$I$I$I I$I$I$I=|3ٔNsb=HÖ[vy~Hm,<,BF{Իr2 J;V]"M܌jԞlO/򍵰 T; G$!1A@Q 0aP`?k ܅>fn\EFu g, b2#dM޾N,yH7OƼ7IJDx&l۳DZIA 4}gڑ_OjRsDKf邰(JaVJGu`|p^EtbT'+VjJǤ| wh"ͦSUuga !p4~iy AE? SQ41 )XGѦh xzی-JgځV]L3 / 8d FųV<]Mߐطp~7qlMϜOzCJG5 XL,X[Ju+xA krwN+hxM.fX7NYמ6@3 yT~|Aa/ymg>ZR)"t~ٯS׃ LAﭿ=wNv Wϗklu')iiU6j1(=YAhia5E&TSB0ڃDŽU0^8%^_\soQG4aB:0$)f?Wj*C@J&>X VWsh7ØDiklCʕ|?ث<A) 6XJBW=dyDy ";ZД2/8:R3y|vWu]Ʀ#kܯW"(Gl1*{^[][9ܼ=$+`4)CgQLǁ TtA/3n 6 B]:l~8U)vk tggz;|D3z߲_rCѤץzcZOk#H(SM˹DP|Ƈ;#Jt]bK}grD@`mP3KY'h MUx(WQ蘭,a{vonlNgl34m3D#t?_郖Hv, =|MtxӬ)l;&VS>=BfR^YTM͉5r;Xz޼d(C};O1j}g>GX!P1e;,ӲVbnђ&G)Xy})]۷Ч'1l(rT 4yڽԈHu"-+PO c$J/yM|Wwzƞ@nx])PkT;zdxK}x+nZbQ/#&^WJ¥#x܈~:B{C ѦS\M'@e A|Dl]@h" k7ӱ TӰHx.jJPxӯ&Kg4ݴdO'_arUY^c(;x(5d2o@ ETUt1 P,kg[I.`VG"Wd#æ6szN j=nFwܙԖ$2FްFQcT^7$`JQbX<kF]I[e2-U)A,)$H?o9Ԓj%BwcoyO~x"dPʊ yT̡44xn`He<) 4T*wjWDzo@1rQUWyE>%TjtĆBdtV/ R?N\?l#Bu3zu7z `MszU|``sYE"?AN+C5,&-H5+UQ:ABc2ASQew[;ڪ`1!54 v\M-MHM!!.!uPkti )3y^ny^ԍYv2U.\&!ч}g{f2.5 D # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import os import sys from PIL import Image, ImageOps import aalib type(b'') # Python >= 2.6 is required here = os.path.dirname(__file__) if not sys.stdout.isatty(): screen = aalib.AsciiScreen elif os.getenv('TERM') == 'linux': screen = aalib.LinuxScreen else: screen = aalib.AnsiScreen screen = screen(width=76, height=24) with open(os.path.join(here, 'python.jpeg'), 'rb') as fp: image = Image.open(fp).convert('L') image = ImageOps.invert(image) image = image.resize(screen.virtual_size) screen.put_image((0, 0), image) print(screen.render()) # vim:ts=4 sts=4 sw=4 et