python-aalib-0.4/ 0000755 0000000 0000000 00000000000 14015753105 013743 5 ustar 00root root 0000000 0000000 python-aalib-0.4/MANIFEST.in 0000644 0000000 0000000 00000000234 14015003472 015473 0 ustar 00root root 0000000 0000000 include 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-INFO 0000644 0000000 0000000 00000001305 14015753105 015037 0 ustar 00root root 0000000 0000000 Metadata-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.py 0000644 0000000 0000000 00000021272 14015750560 015373 0 ustar 00root root 0000000 0000000 # 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/ 0000755 0000000 0000000 00000000000 14015753105 014510 5 ustar 00root root 0000000 0000000 python-aalib-0.4/doc/LICENSE 0000644 0000000 0000000 00000002074 14015750557 015530 0 ustar 00root root 0000000 0000000 Copyright © 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/changelog 0000644 0000000 0000000 00000003303 14015751075 016365 0 ustar 00root root 0000000 0000000 python-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.py 0000644 0000000 0000000 00000003431 14015750560 015460 0 ustar 00root root 0000000 0000000 # 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/ 0000755 0000000 0000000 00000000000 14015753105 014722 5 ustar 00root root 0000000 0000000 python-aalib-0.4/test/Makefile 0000644 0000000 0000000 00000000641 14015007752 016363 0 ustar 00root root 0000000 0000000 # 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.c 0000644 0000000 0000000 00000001771 14015002466 016567 0 ustar 00root root 0000000 0000000 /* 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.py 0000644 0000000 0000000 00000001006 14015750562 016773 0 ustar 00root root 0000000 0000000 # 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.jpeg 0000644 0000000 0000000 00000023202 12722277170 017117 0 ustar 00root root 0000000 0000000 JFIF H H C
%# , #&')*)-0-(0%()( C
((((((((((((((((((((((((((((((((((((((((((((((((((( |+suo
geD oug孄; x][?If: utR]\ 9TnEe+>v*^ ƹ{!}S+y3{͜u=y kI, 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[_<.T 9cy-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.㱳-&KsbJq+j^mk5͖Vcd5K,k?9cb