Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Build image.c as an extension; Fixed Windows support #256

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 25 additions & 17 deletions rainbowstream/c_image.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,34 @@
from os.path import join, dirname, getmtime, exists, expanduser
from .config import *
from .py3patch import *
from .util import get_terminal_size

import ctypes
import sys
import os


def call_c():
"""
Call the C program for converting RGB to Ansi colors
"""
library = expanduser('~/.image.so')
sauce = join(dirname(__file__), 'image.c')
if not exists(library) or getmtime(sauce) > getmtime(library):
build = "cc -fPIC -shared -o %s %s" % (library, sauce)
os.system(build + " >/dev/null 2>&1")
image_c = ctypes.cdll.LoadLibrary(library)
image_c.init()
return image_c.rgb_to_ansi

rgb2short = call_c()
import platform

from rainbowstream_image import rgb_to_ansi

# def call_c():
# """
# Call the C program for converting RGB to Ansi colors
# """
# if platform.system() == 'Windows':
# pass
# # library = f'{get_python_lib()}\image.cp36-win32.pyd'
# # image_c = ctypes.cdll.LoadLibrary(library)
# else:
# library = expanduser('~/.image.so')
# sauce = join(dirname(__file__), 'image.c')
# if not exists(library) or getmtime(sauce) > getmtime(library):
# build = "cc -fPIC -shared -o %s %s" % (library, sauce)
# os.system(build + " >/dev/null 2>&1")
# image_c = ctypes.cdll.LoadLibrary(library)
# image_c.init()
# return image_c.rgb_to_ansi

rgb2short = rgb_to_ansi


def pixel_print(pixel):
Expand Down Expand Up @@ -60,7 +68,7 @@ def image_to_display(path, start=None, length=None):
"""
Display an image
"""
rows, columns = os.popen('stty size', 'r').read().split()
rows, columns = get_terminal_size()
if not start:
start = c['IMAGE_SHIFT']
if not length:
Expand Down
4 changes: 2 additions & 2 deletions rainbowstream/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ def set_config(key, value):
# Save
with open(path, 'w') as out:
json.dump(data, out, indent=4)
os.system('chmod 777 ' + path)
os.chmod(path, 0o777)


def delete_config(key):
Expand All @@ -128,7 +128,7 @@ def delete_config(key):
# Save
with open(path, 'w') as out:
json.dump(data, out, indent=4)
os.system('chmod 777 ' + path)
os.chmod(path, 0o777)


def reload_config():
Expand Down
7 changes: 4 additions & 3 deletions rainbowstream/draw.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from .config import *
from .py3patch import *
from .emoji import *
from .util import get_terminal_size

# Draw global variables
dg = {}
Expand Down Expand Up @@ -446,7 +447,7 @@ def print_thread(partner, me_nick, me_name):
me_name = cycle_color(me_name)
left = ' ' * margin + partner_name + ' ' + partner_nick
right = me_name + ' ' + me_screen_name + ' ' * margin
h, w = os.popen('stty size', 'r').read().split()
h, w = get_terminal_size()
w = int(w)
line = '{}{}{}'.format(
left, ' ' * (w - left_size - right_size - 2 * margin), right)
Expand All @@ -465,7 +466,7 @@ def print_right_message(m):
"""
Print a message on the right of screen
"""
h, w = os.popen('stty size', 'r').read().split()
h, w = get_terminal_size()
w = int(w)
frame_width = w // 3 - dg['frame_margin']
frame_width = max(c['THREAD_MIN_WIDTH'], frame_width)
Expand Down Expand Up @@ -530,7 +531,7 @@ def print_left_message(m):
"""
Print a message on the left of screen
"""
h, w = os.popen('stty size', 'r').read().split()
h, w = get_terminal_size()
w = int(w)
frame_width = w // 3 - dg['frame_margin']
frame_width = max(c['THREAD_MIN_WIDTH'], frame_width)
Expand Down
70 changes: 56 additions & 14 deletions rainbowstream/image.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
* https://github.com/jart/fabulous/blob/master/fabulous/_xterm256.c
* I make a slightly change to fit my module here
*/

#include <Python.h>

typedef struct {
int r;
int g;
Expand All @@ -18,6 +21,7 @@ rgb_t BASIC16[] =
{ 255, 255, 255 } };
rgb_t COLOR_TABLE[256];

/* __declspec(dllexport) */

rgb_t ansi_to_rgb(int xcolor)
{
Expand All @@ -35,6 +39,32 @@ rgb_t ansi_to_rgb(int xcolor)
return res;
}

// int rgb_to_ansi(int r, int g, int b)
PyObject *
rgb_to_ansi(PyObject *self, PyObject *args)
{
int r, g, b;

if (!PyArg_ParseTuple(args, "iii", &r, &g, &b)) {
return NULL;
}

int best_match = 0;
int smallest_distance = 1000000000;
int c, d;
for (c = 16; c < 256; c++) {
d = (COLOR_TABLE[c].r - r)*(COLOR_TABLE[c].r - r) +
(COLOR_TABLE[c].g - g)*(COLOR_TABLE[c].g - g) +
(COLOR_TABLE[c].b - b)*(COLOR_TABLE[c].b - b);
if (d < smallest_distance) {
smallest_distance = d;
best_match = c;
}
}

return Py_BuildValue("i", best_match);
}

int init()
{
int c;
Expand All @@ -44,19 +74,31 @@ int init()
return 0;
}

int rgb_to_ansi(int r, int g, int b)
{
int best_match = 0;
int smallest_distance = 1000000000;
int c, d;
for (c = 16; c < 256; c++) {
d = (COLOR_TABLE[c].r - r)*(COLOR_TABLE[c].r - r) +
(COLOR_TABLE[c].g - g)*(COLOR_TABLE[c].g - g) +
(COLOR_TABLE[c].b - b)*(COLOR_TABLE[c].b - b);
if (d < smallest_distance) {
smallest_distance = d;
best_match = c;
static PyMethodDef ImageMethods[] = {
{"rgb_to_ansi", (PyCFunction) rgb_to_ansi, METH_VARARGS, "Convert RGB to ANSI"},
{NULL, NULL, 0, NULL} /* Sentinel */
};

static struct PyModuleDef ImageModule = {
PyModuleDef_HEAD_INIT,
"rainbowstream_image", /* name of module */
NULL, /* module documentation, may be NULL */
-1, /* size of per-interpreter state of the module,
or -1 if the module keeps state in global variables. */
ImageMethods
};

PyMODINIT_FUNC
PyInit_rainbowstream_image(void)
{
PyObject *m;

m = PyModule_Create(&ImageModule);
if (m == NULL) {
return NULL;
}
}
return best_match;

init();

return m;
}
2 changes: 1 addition & 1 deletion rainbowstream/interactive.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ def init_interactive_shell(d):
"""
readline.set_completer(RainbowCompleter(d).complete)
readline.parse_and_bind('set skip-completed-text on')
if 'libedit' in readline.__doc__:
if readline.__doc__ and 'libedit' in readline.__doc__:
readline.parse_and_bind("bind ^I rl_complete")
else:
readline.parse_and_bind("tab: complete")
3 changes: 2 additions & 1 deletion rainbowstream/pure_image.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from functools import partial
from .config import *
from .py3patch import *
from .util import get_terminal_size

import sys
import os
Expand Down Expand Up @@ -339,7 +340,7 @@ def image_to_display(path, start=None, length=None):
"""
Display an image
"""
rows, columns = os.popen('stty size', 'r').read().split()
rows, columns = get_terminal_size()
if not start:
start = IMAGE_SHIFT
if not length:
Expand Down
2 changes: 1 addition & 1 deletion rainbowstream/rainbow.py
Original file line number Diff line number Diff line change
Expand Up @@ -1761,7 +1761,7 @@ def help():
Help
"""
s = ' ' * 2
h, w = os.popen('stty size', 'r').read().split()
h, w = get_terminal_size()
# Start
usage = '\n'
usage += s + 'Hi boss! I\'m ready to serve you right now!\n'
Expand Down
10 changes: 10 additions & 0 deletions rainbowstream/util.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import json
import shutil
import platform
import os

from twitter.util import printNicely
from .colors import *
Expand Down Expand Up @@ -49,6 +52,13 @@ def format_prefix(listname='', keyword=''):
return formattedPrefix


def get_terminal_size():
if platform.system() == 'Windows':
return shutil.get_terminal_size()
else:
return os.popen('stty size', 'r').read().split()


def add_tweetmode_parameter(kwargs):
"""
Add support for extended mode to Twitter API calls unless explicitly stated in config
Expand Down
26 changes: 16 additions & 10 deletions setup.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
from setuptools import setup, find_packages
# from setuptools import setup, find_packages
from distutils.core import setup, Extension
from setuptools import find_packages
import os
import os.path
import sys
import platform
from shutil import copy, chown
import getpass

image_ext = Extension('rainbowstream_image', sources=['rainbowstream/image.c'])

if sys.version[0] == "2":
from pipes import quote
Expand All @@ -20,22 +27,20 @@
"twitter",
"Pillow",
"PySocks",
"pocket"
"pocket",
"pyreadline"
]

# Default user (considers non virtualenv method)
user = os.environ.get('SUDO_USER', os.environ.get('USER', None))
user = os.environ.get('SUDO_USER', os.environ.get('USER', getpass.getuser()))

# Copy default config if not exists
default = os.path.expanduser("~") + os.sep + '.rainbow_config.json'
if not os.path.isfile(default):
cmd = 'cp rainbowstream/colorset/config ' + default
os.system(cmd)
if user:
cmd = 'chown ' + quote(user) + ' ' + default
os.system(cmd)
cmd = 'chmod 777 ' + default
os.system(cmd)
copy('rainbowstream/colorset/config', default)
if platform.system() != 'Windows' and user:
chown(default, quote(user))
os.chmod(default, 0o777)

# Setup
setup(name='rainbowstream',
Expand Down Expand Up @@ -66,6 +71,7 @@
include_package_data=True,
zip_safe=True,
install_requires=install_requires,
ext_modules=[image_ext],
entry_points="""
# -*- Entry points: -*-
[console_scripts]
Expand Down