python-aalib-0.3.2/0000755000000000000000000000000012727107133014104 5ustar00rootroot00000000000000python-aalib-0.3.2/doc/0000755000000000000000000000000012727107133014651 5ustar00rootroot00000000000000python-aalib-0.3.2/doc/changelog0000644000000000000000000000237612727106552016537 0ustar00rootroot00000000000000python-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.3.2/aalib.py0000644000000000000000000002303212722301647015527 0ustar00rootroot00000000000000# encoding=UTF-8 # Copyright © 2009-2015 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. ''' interface to AAlib, an ASCII art library ''' import ctypes 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): _pack_ = 4 _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): _pack_ = 4 _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.iteritems(): 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 xrange(max(y0, 0), min(y0 + image_height, virtual_height)): p = y * virtual_width for x in xrange(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.iteritems(): 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 xrange(width) ] for y in xrange(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.3.2/test/0000755000000000000000000000000012727107133015063 5ustar00rootroot00000000000000python-aalib-0.3.2/test/test.py0000644000000000000000000000325312722277170016423 0ustar00rootroot00000000000000# encoding=UTF-8 # Copyright © 2010-2015 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. import os import sys from PIL import Image, ImageOps import aalib 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 python-aalib-0.3.2/test/python.jpeg0000644000000000000000000002320212722277170017256 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. ''' *python-aalib* is an interface to `AAlib `_, an ASCII art library. ''' 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() import distutils.core import distutils.command.build_py try: # Python 3.X from distutils.command.build_py import build_py_2to3 as build_py except ImportError: # Python 2.X from distutils.command.build_py import build_py try: f = open('doc/changelog', encoding='UTF-8') except TypeError: f = open('doc/changelog') with f: version = f.readline().split()[1].strip('()') distutils.core.setup( name='python-aalib', version=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(build_py=build_py), ) # vim:ts=4 sts=4 sw=4 et python-aalib-0.3.2/PKG-INFO0000644000000000000000000000130712727107133015202 0ustar00rootroot00000000000000Metadata-Version: 1.1 Name: python-aalib Version: 0.3.2 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