1#!/usr/bin/env python
2#
3# Copyright (c) 2014-2020 Hayaki Saito
4#
5# Permission is hereby granted, free of charge, to any person obtaining a copy of
6# this software and associated documentation files (the "Software"), to deal in
7# the Software without restriction, including without limitation the rights to
8# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9# the Software, and to permit persons to whom the Software is furnished to do so,
10# subject to the following conditions:
11#
12# The above copyright notice and this permission notice shall be included in all
13# copies or substantial portions of the Software.
14#
15# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21#
22
23from ctypes import cdll, c_void_p, c_int, c_byte, c_char_p, POINTER, byref, CFUNCTYPE, string_at
24from ctypes.util import find_library
25
26# limitations
27SIXEL_OUTPUT_PACKET_SIZE     = 16384
28SIXEL_PALETTE_MIN            = 2
29SIXEL_PALETTE_MAX            = 256
30SIXEL_USE_DEPRECATED_SYMBOLS = 1
31SIXEL_ALLOCATE_BYTES_MAX     = 10248 * 1024 * 128  # up to 128M
32SIXEL_WIDTH_LIMIT            = 1000000
33SIXEL_HEIGHT_LIMIT           = 1000000
34
35# loader settings
36SIXEL_DEFALUT_GIF_DELAY      = 1
37
38# return value
39SIXEL_OK              = 0x0000
40SIXEL_FALSE           = 0x1000
41
42# error codes
43SIXEL_RUNTIME_ERROR        = (SIXEL_FALSE         | 0x0100)  # runtime error
44SIXEL_LOGIC_ERROR          = (SIXEL_FALSE         | 0x0200)  # logic error
45SIXEL_FEATURE_ERROR        = (SIXEL_FALSE         | 0x0300)  # feature not enabled
46SIXEL_LIBC_ERROR           = (SIXEL_FALSE         | 0x0400)  # errors caused by curl
47SIXEL_CURL_ERROR           = (SIXEL_FALSE         | 0x0500)  # errors occures in libc functions
48SIXEL_JPEG_ERROR           = (SIXEL_FALSE         | 0x0600)  # errors occures in libjpeg functions
49SIXEL_PNG_ERROR            = (SIXEL_FALSE         | 0x0700)  # errors occures in libpng functions
50SIXEL_GDK_ERROR            = (SIXEL_FALSE         | 0x0800)  # errors occures in gdk functions
51SIXEL_GD_ERROR             = (SIXEL_FALSE         | 0x0900)  # errors occures in gd functions
52SIXEL_STBI_ERROR           = (SIXEL_FALSE         | 0x0a00)  # errors occures in stb_image functions
53SIXEL_STBIW_ERROR          = (SIXEL_FALSE         | 0x0b00)  # errors occures in stb_image_write functions
54
55SIXEL_INTERRUPTED          = (SIXEL_OK            | 0x0001)  # interrupted by a signal
56
57SIXEL_BAD_ALLOCATION       = (SIXEL_RUNTIME_ERROR | 0x0001)  # malloc() failed
58SIXEL_BAD_ARGUMENT         = (SIXEL_RUNTIME_ERROR | 0x0002)  # bad argument detected
59SIXEL_BAD_INPUT            = (SIXEL_RUNTIME_ERROR | 0x0003)  # bad input detected
60SIXEL_BAD_INTEGER_OVERFLOW = (SIXEL_RUNTIME_ERROR | 0x0004)  # integer overflow
61
62SIXEL_NOT_IMPLEMENTED      = (SIXEL_FEATURE_ERROR | 0x0001)  # feature not implemented
63
64def SIXEL_SUCCEEDED(status):
65    return (((status) & 0x1000) == 0)
66
67def SIXEL_FAILED(status):
68    return (((status) & 0x1000) != 0)
69
70# method for finding the largest dimension for splitting,
71# and sorting by that component
72SIXEL_LARGE_AUTO = 0x0   # choose automatically the method for finding the largest dimension
73SIXEL_LARGE_NORM = 0x1   # simply comparing the range in RGB space
74SIXEL_LARGE_LUM  = 0x2   # transforming into luminosities before the comparison
75
76# method for choosing a color from the box
77SIXEL_REP_AUTO           = 0x0  # choose automatically the method for selecting representative color from each box
78SIXEL_REP_CENTER_BOX     = 0x1  # choose the center of the box
79SIXEL_REP_AVERAGE_COLORS = 0x2  # choose the average all the color in the box (specified in Heckbert's paper)
80SIXEL_REP_AVERAGE_PIXELS = 0x3  # choose the average all the pixels in the box
81
82# method for diffusing
83SIXEL_DIFFUSE_AUTO      = 0x0  # choose diffusion type automatically
84SIXEL_DIFFUSE_NONE      = 0x1  # don't diffuse
85SIXEL_DIFFUSE_ATKINSON  = 0x2  # diffuse with Bill Atkinson's method
86SIXEL_DIFFUSE_FS        = 0x3  # diffuse with Floyd-Steinberg method
87SIXEL_DIFFUSE_JAJUNI    = 0x4  # diffuse with Jarvis, Judice & Ninke method
88SIXEL_DIFFUSE_STUCKI    = 0x5  # diffuse with Stucki's method
89SIXEL_DIFFUSE_BURKES    = 0x6  # diffuse with Burkes' method
90SIXEL_DIFFUSE_A_DITHER  = 0x7  # positionally stable arithmetic dither
91SIXEL_DIFFUSE_X_DITHER  = 0x8  # positionally stable arithmetic xor based dither
92
93# quality modes
94SIXEL_QUALITY_AUTO      = 0x0  # choose quality mode automatically
95SIXEL_QUALITY_HIGH      = 0x1  # high quality palette construction
96SIXEL_QUALITY_LOW       = 0x2  # low quality palette construction
97SIXEL_QUALITY_FULL      = 0x3  # full quality palette construction
98SIXEL_QUALITY_HIGHCOLOR = 0x4  # high color
99
100# built-in dither
101SIXEL_BUILTIN_MONO_DARK   = 0x0  # monochrome terminal with dark background
102SIXEL_BUILTIN_MONO_LIGHT  = 0x1  # monochrome terminal with light background
103SIXEL_BUILTIN_XTERM16     = 0x2  # xterm 16color
104SIXEL_BUILTIN_XTERM256    = 0x3  # xterm 256color
105SIXEL_BUILTIN_VT340_MONO  = 0x4  # vt340 monochrome
106SIXEL_BUILTIN_VT340_COLOR = 0x5  # vt340 color
107SIXEL_BUILTIN_G1          = 0x6  # 1bit grayscale
108SIXEL_BUILTIN_G2          = 0x7  # 2bit grayscale
109SIXEL_BUILTIN_G4          = 0x8  # 4bit grayscale
110SIXEL_BUILTIN_G8          = 0x9  # 8bit grayscale
111
112# offset value of pixelFormat
113SIXEL_FORMATTYPE_COLOR     = (0)
114SIXEL_FORMATTYPE_GRAYSCALE = (1 << 6)
115SIXEL_FORMATTYPE_PALETTE   = (1 << 7)
116
117# pixelformat type of input image
118#   NOTE: for compatibility, the value of PIXELFORAMT_COLOR_RGB888 must be 3
119SIXEL_PIXELFORMAT_RGB555   = (SIXEL_FORMATTYPE_COLOR     | 0x01) # 15bpp
120SIXEL_PIXELFORMAT_RGB565   = (SIXEL_FORMATTYPE_COLOR     | 0x02) # 16bpp
121SIXEL_PIXELFORMAT_RGB888   = (SIXEL_FORMATTYPE_COLOR     | 0x03) # 24bpp
122SIXEL_PIXELFORMAT_BGR555   = (SIXEL_FORMATTYPE_COLOR     | 0x04) # 15bpp
123SIXEL_PIXELFORMAT_BGR565   = (SIXEL_FORMATTYPE_COLOR     | 0x05) # 16bpp
124SIXEL_PIXELFORMAT_BGR888   = (SIXEL_FORMATTYPE_COLOR     | 0x06) # 24bpp
125SIXEL_PIXELFORMAT_ARGB8888 = (SIXEL_FORMATTYPE_COLOR     | 0x10) # 32bpp
126SIXEL_PIXELFORMAT_RGBA8888 = (SIXEL_FORMATTYPE_COLOR     | 0x11) # 32bpp
127SIXEL_PIXELFORMAT_ABGR8888 = (SIXEL_FORMATTYPE_COLOR     | 0x12) # 32bpp
128SIXEL_PIXELFORMAT_BGRA8888 = (SIXEL_FORMATTYPE_COLOR     | 0x13) # 32bpp
129SIXEL_PIXELFORMAT_G1       = (SIXEL_FORMATTYPE_GRAYSCALE | 0x00) # 1bpp grayscale
130SIXEL_PIXELFORMAT_G2       = (SIXEL_FORMATTYPE_GRAYSCALE | 0x01) # 2bpp grayscale
131SIXEL_PIXELFORMAT_G4       = (SIXEL_FORMATTYPE_GRAYSCALE | 0x02) # 4bpp grayscale
132SIXEL_PIXELFORMAT_G8       = (SIXEL_FORMATTYPE_GRAYSCALE | 0x03) # 8bpp grayscale
133SIXEL_PIXELFORMAT_AG88     = (SIXEL_FORMATTYPE_GRAYSCALE | 0x13) # 16bpp gray+alpha
134SIXEL_PIXELFORMAT_GA88     = (SIXEL_FORMATTYPE_GRAYSCALE | 0x23) # 16bpp gray+alpha
135SIXEL_PIXELFORMAT_PAL1     = (SIXEL_FORMATTYPE_PALETTE   | 0x00) # 1bpp palette
136SIXEL_PIXELFORMAT_PAL2     = (SIXEL_FORMATTYPE_PALETTE   | 0x01) # 2bpp palette
137SIXEL_PIXELFORMAT_PAL4     = (SIXEL_FORMATTYPE_PALETTE   | 0x02) # 4bpp palette
138SIXEL_PIXELFORMAT_PAL8     = (SIXEL_FORMATTYPE_PALETTE   | 0x03) # 8bpp palette
139
140# palette type
141SIXEL_PALETTETYPE_AUTO     = 0   # choose palette type automatically
142SIXEL_PALETTETYPE_HLS      = 1   # HLS colorspace
143SIXEL_PALETTETYPE_RGB      = 2   # RGB colorspace
144
145# policies of SIXEL encoding
146SIXEL_ENCODEPOLICY_AUTO    = 0   # choose encoding policy automatically
147SIXEL_ENCODEPOLICY_FAST    = 1   # encode as fast as possible
148SIXEL_ENCODEPOLICY_SIZE    = 2   # encode to as small sixel sequence as possible
149
150# method for re-sampling
151SIXEL_RES_NEAREST          = 0   # Use nearest neighbor method
152SIXEL_RES_GAUSSIAN         = 1   # Use guaussian filter
153SIXEL_RES_HANNING          = 2   # Use hanning filter
154SIXEL_RES_HAMMING          = 3   # Use hamming filter
155SIXEL_RES_BILINEAR         = 4   # Use bilinear filter
156SIXEL_RES_WELSH            = 5   # Use welsh filter
157SIXEL_RES_BICUBIC          = 6   # Use bicubic filter
158SIXEL_RES_LANCZOS2         = 7   # Use lanczos-2 filter
159SIXEL_RES_LANCZOS3         = 8   # Use lanczos-3 filter
160SIXEL_RES_LANCZOS4         = 9   # Use lanczos-4 filter
161
162# image format
163SIXEL_FORMAT_GIF           = 0x0 # read only
164SIXEL_FORMAT_PNG           = 0x1 # read/write
165SIXEL_FORMAT_BMP           = 0x2 # read only
166SIXEL_FORMAT_JPG           = 0x3 # read only
167SIXEL_FORMAT_TGA           = 0x4 # read only
168SIXEL_FORMAT_WBMP          = 0x5 # read only with --with-gd configure option
169SIXEL_FORMAT_TIFF          = 0x6 # read only
170SIXEL_FORMAT_SIXEL         = 0x7 # read only
171SIXEL_FORMAT_PNM           = 0x8 # read only
172SIXEL_FORMAT_GD2           = 0x9 # read only with --with-gd configure option
173SIXEL_FORMAT_PSD           = 0xa # read only
174SIXEL_FORMAT_HDR           = 0xb # read only
175
176# loop mode
177SIXEL_LOOP_AUTO            = 0   # honer the setting of GIF header
178SIXEL_LOOP_FORCE           = 1   # always enable loop
179SIXEL_LOOP_DISABLE         = 2   # always disable loop
180
181# setopt flags
182SIXEL_OPTFLAG_INPUT            = 'i'  # -i, --input: specify input file name.
183SIXEL_OPTFLAG_OUTPUT           = 'o'  # -o, --output: specify output file name.
184SIXEL_OPTFLAG_OUTFILE          = 'o'  # -o, --outfile: specify output file name.
185SIXEL_OPTFLAG_7BIT_MODE        = '7'  # -7, --7bit-mode: for 7bit terminals or printers (default)
186SIXEL_OPTFLAG_8BIT_MODE        = '8'  # -8, --8bit-mode: for 8bit terminals or printers
187SIXEL_OPTFLAG_COLORS           = 'p'  # -p COLORS, --colors=COLORS: specify number of colors
188SIXEL_OPTFLAG_MAPFILE          = 'm'  # -m FILE, --mapfile=FILE: specify set of colors
189SIXEL_OPTFLAG_MONOCHROME       = 'e'  # -e, --monochrome: output monochrome sixel image
190SIXEL_OPTFLAG_INSECURE         = 'k'  # -k, --insecure: allow to connect to SSL sites without certs
191SIXEL_OPTFLAG_INVERT           = 'i'  # -i, --invert: assume the terminal background color
192SIXEL_OPTFLAG_HIGH_COLOR       = 'I'  # -I, --high-color: output 15bpp sixel image
193SIXEL_OPTFLAG_USE_MACRO        = 'u'  # -u, --use-macro: use DECDMAC and DEVINVM sequences
194SIXEL_OPTFLAG_MACRO_NUMBER     = 'n'  # -n MACRONO, --macro-number=MACRONO:
195                                      #        specify macro register number
196SIXEL_OPTFLAG_COMPLEXION_SCORE = 'C'  # -C COMPLEXIONSCORE, --complexion-score=COMPLEXIONSCORE:
197                                      #        specify an number argument for the score of
198                                      #        complexion correction.
199SIXEL_OPTFLAG_IGNORE_DELAY     = 'g'  # -g, --ignore-delay: render GIF animation without delay
200SIXEL_OPTFLAG_STATIC           = 'S'  # -S, --static: render animated GIF as a static image
201SIXEL_OPTFLAG_DIFFUSION        = 'd'  # -d DIFFUSIONTYPE, --diffusion=DIFFUSIONTYPE:
202                                      #          choose diffusion method which used with -p option.
203                                      #          DIFFUSIONTYPE is one of them:
204                                      #            auto     -> choose diffusion type
205                                      #                        automatically (default)
206                                      #            none     -> do not diffuse
207                                      #            fs       -> Floyd-Steinberg method
208                                      #            atkinson -> Bill Atkinson's method
209                                      #            jajuni   -> Jarvis, Judice & Ninke
210                                      #            stucki   -> Stucki's method
211                                      #            burkes   -> Burkes' method
212                                      #            a_dither -> positionally stable
213                                      #                        arithmetic dither
214                                      #            x_dither -> positionally stable
215                                      #                        arithmetic xor based dither
216
217SIXEL_OPTFLAG_FIND_LARGEST     = 'f'  # -f FINDTYPE, --find-largest=FINDTYPE:
218                                      #         choose method for finding the largest
219                                      #         dimension of median cut boxes for
220                                      #         splitting, make sense only when -p
221                                      #         option (color reduction) is
222                                      #         specified
223                                      #         FINDTYPE is one of them:
224                                      #           auto -> choose finding method
225                                      #                   automatically (default)
226                                      #           norm -> simply comparing the
227                                      #                   range in RGB space
228                                      #           lum  -> transforming into
229                                      #                   luminosities before the
230                                      #                   comparison
231
232SIXEL_OPTFLAG_SELECT_COLOR     = 's'  # -s SELECTTYPE, --select-color=SELECTTYPE
233                                      #        choose the method for selecting
234                                      #        representative color from each
235                                      #        median-cut box, make sense only
236                                      #        when -p option (color reduction) is
237                                      #        specified
238                                      #        SELECTTYPE is one of them:
239                                      #          auto      -> choose selecting
240                                      #                       method automatically
241                                      #                       (default)
242                                      #          center    -> choose the center of
243                                      #                       the box
244                                      #          average    -> calculate the color
245                                      #                       average into the box
246                                      #          histogram -> similar with average
247                                      #                       but considers color
248                                      #                       histogram
249
250SIXEL_OPTFLAG_CROP             = 'c'  # -c REGION, --crop=REGION:
251                                      #        crop source image to fit the
252                                      #        specified geometry. REGION should
253                                      #        be formatted as '%dx%d+%d+%d'
254
255SIXEL_OPTFLAG_WIDTH            = 'w'  # -w WIDTH, --width=WIDTH:
256                                      #        resize image to specified width
257                                      #        WIDTH is represented by the
258                                      #        following syntax
259                                      #          auto       -> preserving aspect
260                                      #                        ratio (default)
261                                      #          <number>%  -> scale width with
262                                      #                        given percentage
263                                      #          <number>   -> scale width with
264                                      #                        pixel counts
265                                      #          <number>px -> scale width with
266                                      #                        pixel counts
267
268SIXEL_OPTFLAG_HEIGHT           = 'h'  # -h HEIGHT, --height=HEIGHT:
269                                      #         resize image to specified height
270                                      #         HEIGHT is represented by the
271                                      #         following syntax
272                                      #           auto       -> preserving aspect
273                                      #                         ratio (default)
274                                      #           <number>%  -> scale height with
275                                      #                         given percentage
276                                      #           <number>   -> scale height with
277                                      #                         pixel counts
278                                      #           <number>px -> scale height with
279                                      #                         pixel counts
280
281SIXEL_OPTFLAG_RESAMPLING       = 'r'  # -r RESAMPLINGTYPE, --resampling=RESAMPLINGTYPE:
282                                      #        choose resampling filter used
283                                      #        with -w or -h option (scaling)
284                                      #        RESAMPLINGTYPE is one of them:
285                                      #          nearest  -> Nearest-Neighbor
286                                      #                      method
287                                      #          gaussian -> Gaussian filter
288                                      #          hanning  -> Hanning filter
289                                      #          hamming  -> Hamming filter
290                                      #          bilinear -> Bilinear filter
291                                      #                      (default)
292                                      #          welsh    -> Welsh filter
293                                      #          bicubic  -> Bicubic filter
294                                      #          lanczos2 -> Lanczos-2 filter
295                                      #          lanczos3 -> Lanczos-3 filter
296                                      #          lanczos4 -> Lanczos-4 filter
297
298SIXEL_OPTFLAG_QUALITY          = 'q'  # -q QUALITYMODE, --quality=QUALITYMODE:
299                                      #        select quality of color
300                                      #        quanlization.
301                                      #          auto -> decide quality mode
302                                      #                  automatically (default)
303                                      #          low  -> low quality and high
304                                      #                  speed mode
305                                      #          high -> high quality and low
306                                      #                  speed mode
307                                      #          full -> full quality and careful
308                                      #                  speed mode
309
310SIXEL_OPTFLAG_LOOPMODE         = 'l'  # -l LOOPMODE, --loop-control=LOOPMODE:
311                                      #        select loop control mode for GIF
312                                      #        animation.
313                                      #          auto    -> honor the setting of
314                                      #                     GIF header (default)
315                                      #          force   -> always enable loop
316                                      #          disable -> always disable loop
317
318SIXEL_OPTFLAG_PALETTE_TYPE     = 't'  # -t PALETTETYPE, --palette-type=PALETTETYPE:
319                                      #        select palette color space type
320                                      #          auto -> choose palette type
321                                      #                  automatically (default)
322                                      #          hls  -> use HLS color space
323                                      #          rgb  -> use RGB color space
324
325SIXEL_OPTFLAG_BUILTIN_PALETTE  = 'b'  # -b BUILTINPALETTE, --builtin-palette=BUILTINPALETTE:
326                                      #        select built-in palette type
327                                      #          xterm16    -> X default 16 color map
328                                      #          xterm256   -> X default 256 color map
329                                      #          vt340mono  -> VT340 monochrome map
330                                      #          vt340color -> VT340 color map
331                                      #          gray1      -> 1bit grayscale map
332                                      #          gray2      -> 2bit grayscale map
333                                      #          gray4      -> 4bit grayscale map
334                                      #          gray8      -> 8bit grayscale map
335
336SIXEL_OPTFLAG_ENCODE_POLICY    = 'E'  # -E ENCODEPOLICY, --encode-policy=ENCODEPOLICY:
337                                      #        select encoding policy
338                                      #          auto -> choose encoding policy
339                                      #                  automatically (default)
340                                      #          fast -> encode as fast as possible
341                                      #          size -> encode to as small sixel
342                                      #                  sequence as possible
343
344SIXEL_OPTFLAG_BGCOLOR          = 'B'  # -B BGCOLOR, --bgcolor=BGCOLOR:
345                                      #        specify background color
346                                      #        BGCOLOR is represented by the
347                                      #        following syntax
348                                      #          #rgb
349                                      #          #rrggbb
350                                      #          #rrrgggbbb
351                                      #          #rrrrggggbbbb
352                                      #          rgb:r/g/b
353                                      #          rgb:rr/gg/bb
354                                      #          rgb:rrr/ggg/bbb
355                                      #          rgb:rrrr/gggg/bbbb
356
357SIXEL_OPTFLAG_PENETRATE        = 'P'  # -P, --penetrate:
358                                      #        penetrate GNU Screen using DCS
359                                      #        pass-through sequence
360SIXEL_OPTFLAG_PIPE_MODE        = 'D'  # -D, --pipe-mode: (deprecated)
361                                      #         read source images from stdin continuously
362SIXEL_OPTFLAG_VERBOSE          = 'v'  # -v, --verbose: show debugging info
363SIXEL_OPTFLAG_VERSION          = 'V'  # -V, --version: show version and license info
364SIXEL_OPTFLAG_HELP             = 'H'  # -H, --help: show this help
365
366if not find_library('sixel'):
367    raise ImportError("libsixel not found.")
368
369# load shared library
370_sixel = cdll.LoadLibrary(find_library('sixel'))
371
372# convert error status code int formatted string
373def sixel_helper_format_error(status):
374    _sixel.sixel_helper_format_error.restype = c_char_p;
375    _sixel.sixel_helper_format_error.argtypes = [c_int];
376    return _sixel.sixel_helper_format_error(status)
377
378
379# compute pixel depth from pixelformat
380def sixel_helper_compute_depth(pixelformat):
381    _sixel.sixel_helper_compute_depth.restype = c_int
382    _sixel.sixel_encoder_encode.argtypes = [c_int]
383    return _sixel.sixel_helper_compute_depth(pixelformat)
384
385
386# create new output context object
387def sixel_output_new(fn_write, priv=None, allocator=c_void_p(None)):
388    def _fn_write_local(data, size, priv_from_c):
389        fn_write(string_at(data, size), priv)
390        return size
391    sixel_write_function = CFUNCTYPE(c_int, c_char_p, c_int, c_void_p)
392    _sixel.sixel_output_new.restype = c_int
393    _sixel.sixel_output_new.argtypes = [POINTER(c_void_p), sixel_write_function, c_void_p, c_void_p]
394    output = c_void_p(None)
395    _fn_write = sixel_write_function(_fn_write_local)
396    _fn_write.restype = c_int
397    _fn_write.argtypes = [sixel_write_function, c_void_p, c_void_p]
398    status = _sixel.sixel_output_new(byref(output), _fn_write, c_void_p(None), allocator)
399    if SIXEL_FAILED(status):
400        message = sixel_helper_format_error(status)
401        raise RuntimeError(message)
402    output.__fn_write = _fn_write
403    return output
404
405
406# increase reference count of output object (thread-unsafe)
407def sixel_output_ref(output):
408    _sixel.sixel_output_ref.restype = None
409    _sixel.sixel_output_ref.argtypes = [c_void_p]
410    _sixel.sixel_output_ref(output)
411
412
413# decrease reference count of output object (thread-unsafe)
414def sixel_output_unref(output):
415    _sixel.sixel_output_unref.restype = None
416    _sixel.sixel_output_unref.argtypes = [c_void_p]
417    _sixel.sixel_output_unref(output)
418    output.__fn_write = None
419
420
421# get 8bit output mode which indicates whether it uses C1 control characters
422def sixel_output_get_8bit_availability(output):
423    _sixel.sixel_output_get_8bit_availability.restype = None
424    _sixel.sixel_output_get_8bit_availability.argtypes = [c_void_p]
425    _sixel.sixel_output_get_8bit_availability(output)
426
427
428# set 8bit output mode state
429def sixel_output_set_8bit_availability(output):
430    _sixel.sixel_output_set_8bit_availability.restype = None
431    _sixel.sixel_output_set_8bit_availability.argtypes = [c_void_p, c_int]
432    _sixel.sixel_output_set_8bit_availability(output)
433
434
435# set whether limit arguments of DECGRI('!') to 255
436def sixel_output_set_gri_arg_limit(output):
437    _sixel.sixel_output_set_gri_arg_limit.restype = None
438    _sixel.sixel_output_set_gri_arg_limit.argtypes = [c_void_p, c_int]
439    _sixel.sixel_output_set_gri_arg_limit(output)
440
441
442# set GNU Screen penetration feature enable or disable
443def sixel_output_set_penetrate_multiplexer(output):
444    _sixel.sixel_output_set_penetrate_multiplexer.restype = None
445    _sixel.sixel_output_set_penetrate_multiplexer.argtypes = [c_void_p, c_int]
446    _sixel.sixel_output_set_penetrate_multiplexer(output)
447
448
449# set whether we skip DCS envelope
450def sixel_output_set_skip_dcs_envelope(output):
451    _sixel.sixel_output_set_skip_dcs_envelope.restype = None
452    _sixel.sixel_output_set_skip_dcs_envelope.argtypes = [c_void_p, c_int]
453    _sixel.sixel_output_set_skip_dcs_envelope(output)
454
455
456# set palette type: RGB or HLS
457def sixel_output_set_palette_type(output):
458    _sixel.sixel_output_set_palette_type.restype = None
459    _sixel.sixel_output_set_palette_type.argtypes = [c_void_p, c_int]
460    _sixel.sixel_output_set_palette_type(output)
461
462
463# set encodeing policy: auto, fast or size
464def sixel_output_set_encode_policy(output):
465    _sixel.sixel_output_set_encode_policy.restype = None
466    _sixel.sixel_output_set_encode_policy.argtypes = [c_void_p, c_int]
467    _sixel.sixel_output_set_encode_policy(output)
468
469
470# create dither context object
471def sixel_dither_new(ncolors, allocator=None):
472    _sixel.sixel_dither_new.restype = c_int
473    _sixel.sixel_dither_new.argtypes = [POINTER(c_void_p), c_int, c_void_p]
474    dither = c_void_p(None)
475    status = _sixel.sixel_dither_new(byref(dither), ncolors, allocator)
476    if SIXEL_FAILED(status):
477        message = sixel_helper_format_error(status)
478        raise RuntimeError(message)
479    return dither
480
481
482# get built-in dither context object
483def sixel_dither_get(builtin_dither):
484    _sixel.sixel_dither_get.restype = c_void_p
485    _sixel.sixel_dither_get.argtypes = [c_int]
486    return _sixel.sixel_dither_get(builtin_dither)
487
488
489# destroy dither context object
490def sixel_dither_destroy(dither):
491    _sixel.sixel_dither_destroy.restype = None
492    _sixel.sixel_dither_destroy.argtypes = [c_void_p]
493    return _sixel.sixel_dither_destroy(dither)
494
495
496# increase reference count of dither context object (thread-unsafe)
497def sixel_dither_ref(dither):
498    _sixel.sixel_dither_ref.restype = None
499    _sixel.sixel_dither_ref.argtypes = [c_void_p]
500    return _sixel.sixel_dither_ref(dither)
501
502
503# decrease reference count of dither context object (thread-unsafe)
504def sixel_dither_unref(dither):
505    _sixel.sixel_dither_unref.restype = None
506    _sixel.sixel_dither_unref.argtypes = [c_void_p]
507    return _sixel.sixel_dither_unref(dither)
508
509
510# initialize internal palette from specified pixel buffer
511def sixel_dither_initialize(dither, data, width, height, pixelformat,
512                            method_for_largest=SIXEL_LARGE_AUTO,
513                            method_for_rep=SIXEL_REP_AUTO,
514                            quality_mode=SIXEL_QUALITY_AUTO):
515    _sixel.sixel_dither_initialize.restype = c_int
516    _sixel.sixel_dither_initialize.argtypes = [c_void_p, c_char_p, c_int, c_int, c_int,
517                                              c_int, c_int, c_int]
518    status = _sixel.sixel_dither_initialize(dither, data, width, height, pixelformat,
519                                            method_for_largest,
520                                            method_for_rep,
521                                            quality_mode)
522    if SIXEL_FAILED(status):
523        message = sixel_helper_format_error(status)
524        raise RuntimeError(message)
525
526
527# set diffusion type, choose from enum methodForDiffuse
528def sixel_dither_set_diffusion_type(dither, method_for_diffuse):
529    _sixel.sixel_dither_set_diffusion_type.restype = None
530    _sixel.sixel_dither_set_diffusion_type.argtypes = [c_void_p, c_int]
531    _sixel.sixel_dither_set_diffusion_type(dither, method_for_diffuse)
532
533
534# get number of palette colors
535def sixel_dither_get_num_of_palette_colors(dither):
536    _sixel.sixel_dither_get_num_of_palette_colors.restype = c_int
537    _sixel.sixel_dither_get_num_of_palette_colors.argtypes = [c_void_p]
538    return _sixel.sixel_dither_get_num_of_palette_colors(dither)
539
540
541# get number of histogram colors */
542def sixel_dither_get_num_of_histogram_colors(dither):
543    _sixel.sixel_dither_get_num_of_histogram_colors.restype = c_int
544    _sixel.sixel_dither_get_num_of_histogram_colors.argtypes = [c_void_p]
545    return _sixel.sixel_dither_get_num_of_histogram_colors(dither)
546
547
548def sixel_dither_get_palette(dither):
549    _sixel.sixel_dither_get_palette.restype = c_char_p
550    _sixel.sixel_dither_get_palette.argtypes = [c_void_p]
551    cpalette = _sixel.sixel_dither_get_palette(dither)
552    return [ord(c) for c in cpalette]
553
554
555def sixel_dither_set_palette(dither, palette):
556    _sixel.sixel_dither_set_palette.restype = None
557    _sixel.sixel_dither_set_palette.argtypes = [c_void_p, c_char_p]
558    cpalette = ''.join(map(chr, palette))
559    _sixel.sixel_dither_set_palette(dither, cpalette)
560
561
562def sixel_dither_set_complexion_score(dither, score):
563    _sixel.sixel_dither_set_complexion_score.restype = None
564    _sixel.sixel_dither_set_complexion_score.argtypes = [c_void_p, c_int]
565    _sixel.sixel_dither_set_complexion_score(dither, score)
566
567
568def sixel_dither_set_body_only(dither, bodyonly):
569    _sixel.sixel_dither_set_body_only.restype = None
570    _sixel.sixel_dither_set_body_only.argtypes = [c_void_p, c_int]
571    _sixel.sixel_dither_set_body_only(dither, bodyonly)
572
573
574def sixel_dither_set_optimize_palette(dither, do_opt):
575    _sixel.sixel_dither_set_optimize_palette.restype = None
576    _sixel.sixel_dither_set_optimize_palette.argtypes = [c_void_p, c_int]
577    _sixel.sixel_dither_set_optimize_palette(dither, do_opt)
578
579
580def sixel_dither_set_pixelformat(dither, pixelformat):
581    _sixel.sixel_dither_set_pixelformat.restype = None
582    _sixel.sixel_dither_set_pixelformat.argtypes = [c_void_p, c_int]
583    _sixel.sixel_dither_set_pixelformat(dither, pixelformat)
584
585
586def sixel_dither_set_transparent(dither, transparent):
587    _sixel.sixel_dither_set_transparent.restype = None
588    _sixel.sixel_dither_set_transparent.argtypes = [c_void_p, c_int]
589    _sixel.sixel_dither_set_transparent(dither, transparent)
590
591
592# convert pixels into sixel format and write it to output context
593def sixel_encode(pixels, width, height, depth, dither, output):
594    _sixel.sixel_encode.restype = c_int
595    _sixel.sixel_encode.argtypes = [c_char_p, c_int, c_int, c_int, c_void_p, c_void_p]
596    return _sixel.sixel_encode(pixels, width, height, depth, dither, output)
597
598
599# create encoder object
600def sixel_encoder_new(allocator=c_void_p(None)):
601    _sixel.sixel_encoder_new.restype = c_int
602    _sixel.sixel_encoder_new.argtypes = [POINTER(c_void_p), c_void_p]
603    encoder = c_void_p(None)
604    status = _sixel.sixel_encoder_new(byref(encoder), allocator)
605    if SIXEL_FAILED(status):
606        message = sixel_helper_format_error(status)
607        raise RuntimeError(message)
608    return encoder
609
610
611# increase reference count of encoder object (thread-unsafe)
612def sixel_encoder_ref(encoder):
613    _sixel.sixel_encoder_ref.restype = None
614    _sixel.sixel_encoder_ref.argtypes = [c_void_p]
615    _sixel.sixel_encoder_ref(encoder)
616
617
618# decrease reference count of encoder object (thread-unsafe)
619def sixel_encoder_unref(encoder):
620    _sixel.sixel_encoder_unref.restype = None
621    _sixel.sixel_encoder_unref.argtypes = [c_void_p]
622    _sixel.sixel_encoder_unref(encoder)
623
624
625# set an option flag to encoder object
626def sixel_encoder_setopt(encoder, flag, arg=None):
627    _sixel.sixel_encoder_setopt.restype = c_int
628    _sixel.sixel_encoder_setopt.argtypes = [c_void_p, c_int, c_char_p]
629    flag = ord(flag)
630    if arg:
631        arg = str(arg).encode('utf-8')
632    status = _sixel.sixel_encoder_setopt(encoder, flag, arg)
633    if SIXEL_FAILED(status):
634        message = sixel_helper_format_error(status)
635        raise RuntimeError(message)
636
637
638# load source data from specified file and encode it to SIXEL format
639def sixel_encoder_encode(encoder, filename):
640    import locale
641    language, encoding = locale.getdefaultlocale()
642
643    _sixel.sixel_encoder_encode.restype = c_int
644    _sixel.sixel_encoder_encode.argtypes = [c_void_p, c_char_p]
645    status = _sixel.sixel_encoder_encode(encoder, filename.encode(encoding))
646    if SIXEL_FAILED(status):
647        message = sixel_helper_format_error(status)
648        raise RuntimeError(message)
649
650
651# encode specified pixel data to SIXEL format
652def sixel_encoder_encode_bytes(encoder, buf, width, height, pixelformat, palette):
653
654    depth = sixel_helper_compute_depth(pixelformat)
655
656    if depth <= 0:
657        raise ValueError("invalid pixelformat value : %d" % pixelformat)
658
659    if len(buf) < width * height * depth:
660        raise ValueError("buf.len is too short : %d < %d * %d * %d" % (buf.len, width, height, depth))
661
662    if not hasattr(buf, "readonly") or buf.readonly:
663        cbuf = c_void_p.from_buffer_copy(buf)
664    else:
665        cbuf = c_void_p.from_buffer(buf)
666
667    if palette:
668        cpalettelen = len(palette)
669        cpalette = (c_byte * cpalettelen)(*palette)
670    else:
671        cpalettelen = None
672        cpalette = None
673
674    _sixel.sixel_encoder_encode_bytes.restype = c_int
675    _sixel.sixel_encoder_encode.argtypes = [c_void_p, c_void_p, c_int, c_int, c_int, c_void_p, c_int]
676
677    status = _sixel.sixel_encoder_encode_bytes(encoder, buf, width, height, pixelformat, cpalette, cpalettelen)
678    if SIXEL_FAILED(status):
679        message = sixel_helper_format_error(status)
680        raise RuntimeError(message)
681
682
683# create decoder object
684def sixel_decoder_new(allocator=c_void_p(None)):
685    _sixel.sixel_decoder_new.restype = c_int
686    _sixel.sixel_decoder_new.argtypes = [POINTER(c_void_p), c_void_p]
687    decoder = c_void_p(None)
688    status = _sixel.sixel_decoder_new(byref(decoder), c_void_p(None))
689    if SIXEL_FAILED(status):
690        message = sixel_helper_format_error(status)
691        raise RuntimeError(message)
692    return decoder
693
694
695# increase reference count of decoder object (thread-unsafe)
696def sixel_decoder_ref(decoder):
697    _sixel.sixel_decoder_ref.restype = None
698    _sixel.sixel_decoder_ref.argtypes = [c_void_p]
699    _sixel.sixel_decoder_ref(decoder)
700
701
702# decrease reference count of decoder object (thread-unsafe)
703def sixel_decoder_unref(decoder):
704    _sixel.sixel_decoder_unref.restype = None
705    _sixel.sixel_decoder_unref.argtypes = [c_void_p]
706    _sixel.sixel_decoder_unref(decoder)
707
708
709# set an option flag to decoder object
710def sixel_decoder_setopt(decoder, flag, arg=None):
711    _sixel.sixel_decoder_setopt.restype = c_int
712    _sixel.sixel_decoder_setopt.argtypes = [c_void_p, c_int, c_char_p]
713    flag = ord(flag)
714    if arg:
715        arg = str(arg).encode('utf-8')
716    status = _sixel.sixel_decoder_setopt(decoder, flag, arg)
717    if SIXEL_FAILED(status):
718        message = sixel_helper_format_error(status)
719        raise RuntimeError(message)
720
721
722# load source data from stdin or the file
723def sixel_decoder_decode(decoder, infile=None):
724    _sixel.sixel_decoder_decode.restype = c_int
725    _sixel.sixel_decoder_decode.argtypes = [c_void_p]
726    if infile:
727        sixel_decoder_setopt(decoder, SIXEL_OPTFLAG_INPUT, infile)
728    status = _sixel.sixel_decoder_decode(decoder)
729    if SIXEL_FAILED(status):
730        message = sixel_helper_format_error(status)
731        raise RuntimeError(message)
732