def output_sixel(data, im, tw, th): from libsixel import sixel_dither_initialize, sixel_dither_set_palette, sixel_dither_new, SIXEL_BUILTIN_G8, SIXEL_BUILTIN_G1, SIXEL_PIXELFORMAT_RGB888, SIXEL_PIXELFORMAT_RGBA8888, sixel_encode, sixel_dither_unref, sixel_output_new, sixel_dither_get, sixel_dither_set_pixelformat, SIXEL_PIXELFORMAT_PAL8, SIXEL_PIXELFORMAT_G8, SIXEL_PIXELFORMAT_G1 s = BytesIO() if im.mode == 'P': im2 = im.convert('RGB') im = im2 im.thumbnail(size=(tw, th), resample=Image.LANCZOS) data = im.tobytes() output = sixel_output_new(lambda data, s : s.write(data), s) if im.mode == 'RGB': dither = sixel_dither_new(256) sixel_dither_initialize(dither, data, tw, th, SIXEL_PIXELFORMAT_RGB888) elif im.mode == 'RGBA': dither = sixel_dither_new(256) sixel_dither_initialize(dither, data, tw, th, SIXEL_PIXELFORMAT_RGBA8888) elif im.mode == 'P': print("Its broken") sys.exit(1) palette = im.getpalette() print(">>", type(palette), "<<") dither = sixel_dither_new(256) print(">>", type(dither), "<< ") sixel_dither_set_palette(dither, palette) sixel_dither_set_pixelformat(dither, SIXEL_PIXELFORMAT_PAL8) elif im.mode == 'L': dither = sixel_dither_get(SIXEL_BUILTIN_G8) sixel_dither_set_pixelformat(dither, SIXEL_PIXELFORMAT_G8) elif im.mode == '1': dither = sixel_dither_get(SIXEL_BUILTIN_G1) sixel_dither_set_pixelformat(dither, SIXEL_PIXELFORMAT_G1) sixel_encode(data, tw, th, 1, dither, output) print(s.getvalue().decode('ascii')) sixel_dither_unref(dither)
def display_in_terminal(obj): """ Convert and display an output tensor from BigGAN in the terminal. This function use `libsixel` and will only work in a libsixel-compatible terminal. Please refer to https://github.com/saitoha/libsixel for more details. Params: obj: tensor or numpy array of shape (batch_size, channels, height, width) file_name: path and beggingin of filename to save. Images will be saved as `file_name_{image_number}.png` """ try: import PIL from libsixel import (sixel_output_new, sixel_dither_new, sixel_dither_initialize, sixel_dither_set_palette, sixel_dither_set_pixelformat, sixel_dither_get, sixel_encode, sixel_dither_unref, sixel_output_unref, SIXEL_PIXELFORMAT_RGBA8888, SIXEL_PIXELFORMAT_RGB888, SIXEL_PIXELFORMAT_PAL8, SIXEL_PIXELFORMAT_G8, SIXEL_PIXELFORMAT_G1) except ImportError: raise ImportError( "Display in Terminal requires Pillow, libsixel " "and a libsixel compatible terminal. " "Please read info at https://github.com/saitoha/libsixel " "and install with pip install Pillow libsixel-python") s = BytesIO() images = convert_to_images(obj) widths, heights = zip(*(i.size for i in images)) output_width = sum(widths) output_height = max(heights) output_image = PIL.Image.new('RGB', (output_width, output_height)) x_offset = 0 for im in images: output_image.paste(im, (x_offset, 0)) x_offset += im.size[0] try: data = output_image.tobytes() except NotImplementedError: data = output_image.tostring() output = sixel_output_new(lambda data, s: s.write(data), s) try: if output_image.mode == 'RGBA': dither = sixel_dither_new(256) sixel_dither_initialize(dither, data, output_width, output_height, SIXEL_PIXELFORMAT_RGBA8888) elif output_image.mode == 'RGB': dither = sixel_dither_new(256) sixel_dither_initialize(dither, data, output_width, output_height, SIXEL_PIXELFORMAT_RGB888) elif output_image.mode == 'P': palette = output_image.getpalette() dither = sixel_dither_new(256) sixel_dither_set_palette(dither, palette) sixel_dither_set_pixelformat(dither, SIXEL_PIXELFORMAT_PAL8) elif output_image.mode == 'L': dither = sixel_dither_get(SIXEL_BUILTIN_G8) sixel_dither_set_pixelformat(dither, SIXEL_PIXELFORMAT_G8) elif output_image.mode == '1': dither = sixel_dither_get(SIXEL_BUILTIN_G1) sixel_dither_set_pixelformat(dither, SIXEL_PIXELFORMAT_G1) else: raise RuntimeError('unexpected output_image mode') try: sixel_encode(data, output_width, output_height, 1, dither, output) print(s.getvalue().decode('ascii')) finally: sixel_dither_unref(dither) finally: sixel_output_unref(output)
def image_to_display(path, start=None, length=None): """ Display an image """ rows, columns = os.popen('stty size', 'r').read().split() if not start: start = c['IMAGE_SHIFT'] if not length: length = int(columns) - 2 * start i = Image.open(path) i = i.convert('RGBA') w, h = i.size i.load() width = min(w, length) height = int(float(h) * (float(width) / float(w))) if c['IMAGE_RESIZE_TO_FIT'] is True: # If it image won't fit in the terminal without scrolling shrink it # Subtract 3 from rows so the tweet message fits in too. h = 2 * (int(rows) - 3) if height >= h: width = int(float(width) * (float(h) / float(height))) height = h if (height <= 0) or (width <= 0): raise ValueError("image has negative dimensions") height = min(height, c['IMAGE_MAX_HEIGHT']) # Sixel if c['IMAGE_ON_TERM'] == 'sixel': import fcntl, struct, termios from io import BytesIO from libsixel import sixel_dither_new, sixel_dither_initialize, sixel_encode, sixel_output_new, SIXEL_PIXELFORMAT_RGBA8888 from resizeimage import resizeimage # FIXME: rows and columns are gotten a second time. Maybe use this at # the begining of function instead of the call to stty size farg = struct.pack("HHHH", 0, 0, 0, 0) fd_stdout = sys.stdout.fileno() fretint = fcntl.ioctl(fd_stdout, termios.TIOCGWINSZ, farg) rows, columns, xpixels, ypixels = struct.unpack("HHHH", fretint) max_width_pixels = width * (xpixels // columns) max_height_pixels = height * (ypixels // rows) # FIXME: This way is preferable to avoid an addition dependency, but it doesn't work correctly # i = i.resize((max_width_pixels, max_height_pixels), Image.ANTIALIAS) i = resizeimage.resize_thumbnail(i, [max_width_pixels, max_height_pixels]) sixel = BytesIO() dither = sixel_dither_new(256) sixel_dither_initialize(dither, i.tobytes(), i.width, i.height, SIXEL_PIXELFORMAT_RGBA8888) sixel_encode(i.tobytes(), i.width, i.height, 1, dither, sixel_output_new(lambda imgdata, sixel: sixel.write(imgdata), sixel)) sys.stdout.write('%s%s' % (' ' * start, sixel.getvalue().decode('ascii'))) # SGR else: i = i.resize((width, height), Image.ANTIALIAS) for real_y in xrange(height // 2): sys.stdout.write(' ' * start) for x in xrange(width): y = real_y * 2 p0 = i.getpixel((x, y)) p1 = i.getpixel((x, y + 1)) block_print(p1, p0) sys.stdout.write('\n')