From cfa70ef92fed3307f7e4c04a41a284a3a1f95355 Mon Sep 17 00:00:00 2001 From: Mattias Andrée Date: Sun, 2 Nov 2014 21:43:08 +0100 Subject: c for performance MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mattias Andrée --- src/assemble | 206 ----------------------------------- src/assemble.c | 332 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/splashtool | 4 +- 3 files changed, 335 insertions(+), 207 deletions(-) delete mode 100755 src/assemble create mode 100644 src/assemble.c (limited to 'src') diff --git a/src/assemble b/src/assemble deleted file mode 100755 index 6a64d6d..0000000 --- a/src/assemble +++ /dev/null @@ -1,206 +0,0 @@ -#!/usr/bin/env python3 -# -*- python -*- -''' -splashtool – A simple tool for creating SYSLINUX splashes without fuss - -Copyright © 2013, 2014 Mattias Andrée (maandree@member.fsf.org) - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -''' - -import sys - - -def join(fg, bg, alpha): - t = alpha * linear(fg) + (255 - alpha) * linear(bg) - t /= 255 - if t <= 0.00304: - t *= 12.92 - else: - t = 1.055 * t ** (1 / 2.4) - 0.055 - return int(255 * t + 0.5) - -def linear(c): - if c <= 10: - return c / (255 * 12.92) - return ((c + 14.025) / 269.025) ** 2.4 - -def subpixels(p): - return ((p >> 24) & 255, (p >> 16) & 255, (p >> 8) & 255, (p >> 0) & 255) - -def buffer_join(layer, base, offx, offy): - for x in range(len(layer)): - if x + offx >= len(base): - break - layer_column = layer[x] - base_column = base[x + offx] - for y in range(len(layer_column)): - if y + offy >= len(base_column): - break - (la, lr, lg, lb) = subpixels(layer_column[y]) - (ba, br, bg, bb) = subpixels(base_column[y + offy]) - r = join(lr, br, la) - g = join(lg, bg, la) - b = join(lb, bb, la) - base_column[y + offy] = (255 << 24) | (r << 16) | (g << 8) | b - -def widescreen(img): - rc = [[0] * (480 * 16 // 9) for i in range(480)] - for y in range(480): - e = 0 - for x in range(640): - rc[x + e][y] = img[x][y] - if x % 3 == 2: - argb = img[x][y] - if x < 639: - (a1, r1, g1, b1) = subpixels(argb) - (a2, r2, g2, b2) = subpixels(img[x + x1][y]) - a = ((a1 + a2) // 2) << 24 - r = ((r1 + r2) // 2) << 16 - g = ((g1 + g2) // 2) << 8 - b = ((b1 + b2) // 2) << 0 - argb = a | r | g | b - e += 1 - rc[x + e][y] = argb - return rc - -def load_p6(filename): - with open(filename, 'rb') as file: - data = file.read() - text = data.decode('utf-8', 'replace') - text = text[:100].replace('\t', ' ').replace('\r', ' ').replace('\n', ' ') - text = [word for word in text.split(' ') if not word == ''] - width, height = int(text[1]), int(text[2]) - data = list(data) - lines = 0 - while lines < 3: - if data[0] == ord('\n'): - lines += 1 - data[:] = data[1:] - img = [None] * height - def parse_row(row): - rc = [0] * (len(row) // 3) - for i in range(len(rc)): - rc[i] += row[i * 3 + 0] << 16 - rc[i] += row[i * 3 + 1] << 8 - rc[i] += row[i * 3 + 2] << 0 - return rc - for y in range(height): - img[y] = parse_row(data[:width * 3]) - data[:] = data[width * 3:] - rc = [[0] * height for i in range(width)] - for y in range(height): - for x in range(width): - rc[x][y] = img[y][x] - return rc - -# Read image data. -splash = input() -width = int(input()) -height = int(input()) -rows = [input() for i in range(height)] - -# Read font data. -chars = int(input()) -charx = int(input()) -chary = int(input()) -charmap = [[0] * chary for i in range(chars)] -for i in range(chars): - for y in range(chary): - line = input() - charmap[i][y] = sum((0 if line[x] == ' ' else 1) << x for x in range(charx)) - -# The overlay should be centered on the background. -offx = (640 - width * charx) // 2 -offy = (480 - height * chary) // 2 - -# Buffers for layers. -splash = load_p6(splash) -background = [[0] * (height * chary) for i in range(width * charx)] -foreground = [[0] * (height * chary) for i in range(width * charx)] -shadow = [[0] * (height * chary) for i in range(width * charx)] - -# Colours. -fore = 0 -back = 0 -foreback = 0 - -# Fill largers. -for y in range(height): - x = 0 - row = rows[y] - escape = False - for i in range(len(row)): - c = row[i] - if c == '\033': - fore = foreback >> 32 - back = foreback & ((1 << 32) - 1) - escape = not escape - foreback = 0 - elif escape: - if c == '#': - continue - foreback <<= 4 - foreback |= (ord(c) & 15) + (0 if c <= '9' else 9) - foreback &= (1 << 64) - 1 - else: - ci = ord(c) % chars - if c == '┌': ci = 218 - elif c == '─': ci = 196 - elif c == '┐': ci = 191 - elif c == '│': ci = 179 - elif c == '├': ci = 195 - elif c == '┤': ci = 180 - elif c == '└': ci = 192 - elif c == '┘': ci = 217 - char = charmap[ci] - for yi in range(chary): - for xi in range(charx): - xo = (char[yi] >> xi) & 1 - t = offx + x * charx + xi + xo - rgb = splash[639 if t > 639 else t][offy + y * chary + yi] - _a, r, g, b = subpixels(rgb) - if xo == 1: - shadow[x * charx + xi][y * chary + yi] = 128 << 24 - (c_, i_) = (fore, foreground) if xo == 1 else (back, background) - ca, cr, cg, cb = subpixels(c_) - r = join(cr, r, ca) - g = join(cg, g, ca) - b = join(cb, b, ca) - rgb = (255 << 24) | (r << 16) | (g << 8) | b - i_[x * charx + xi][y * chary + yi] = rgb - x += 1 - -# Apply layers. -buffer_join(background, splash, offx, offy) -buffer_join(shadow, splash, offx + 1, offy + 1) -buffer_join(foreground, splash, offx, offy) - -# Make widescreen preview. -if sys.argv[2].lower().startswith('-w') or sys.argv[2].lower().startswith('--w'): - splash = widescreen(splash) - -# Print image. -width, height = len(splash), len(splash[0]) -print('P3') -print('%i %i' % (width, height)) -print('255') -trans = ['%i' % i for i in range(256)] -for y in range(height): - for x in range(width): - (a, r, g, b) = subpixels(splash[x][y]) - print(trans[r]) - print(trans[g]) - print(trans[b]) - diff --git a/src/assemble.c b/src/assemble.c new file mode 100644 index 0000000..e08d2d3 --- /dev/null +++ b/src/assemble.c @@ -0,0 +1,332 @@ +/** + * splashtool – A simple tool for creating SYSLINUX splashes without fuss + * + * Copyright © 2013, 2014 Mattias Andrée (maandree@member.fsf.org) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include + + +#define WIDTH 640 +#define HEIGHT 480 + + +static __attribute__((const)) double linear(unsigned long c) +{ + if (c <= 10) + return (double)c / (255. * 12.92); + return pow(((double)c + 14.025) / 269.025, 2.4); +} + + +static __attribute__((const)) unsigned long join(unsigned long fg, unsigned long bg, unsigned long alpha) +{ + double t = (double)alpha * linear(fg) + (double)(255 - alpha) * linear(bg); + t /= 255.; + if (t <= 0.00304) + t *= 12.92; + else + t = 1.055 * pow(t, 1.0 / 2.4) - 0.055; + return (unsigned long)(255. * t + 0.5); +} + + +static inline void subpixels(unsigned long p, unsigned long* a, + unsigned long* r, unsigned long* g, unsigned long* b) +{ + *a = (p >> 24) & 255; + *r = (p >> 16) & 255; + *g = (p >> 8) & 255; + *b = (p >> 0) & 255; +} + + +static void buffer_join(unsigned long* restrict restrict* layer, unsigned long* restrict* restrict base, + unsigned long width, unsigned long height, unsigned long offx, unsigned long offy) +{ + unsigned long x, y, a, r, g, b; + unsigned long* restrict layer_column; + unsigned long* restrict base_column; + base += offx; + for (x = 0; x < width; x++) + { + layer_column = *layer++; + base_column = *base++ + offy; + for (y = 0; y < height; y++, base_column++) + { + subpixels(*layer_column++, &a, &r, &g, &b); + if (a == 255) + *base_column = (r << 16) | (g << 8) | b; + } + } +} + + +static void widescreen(unsigned long* restrict* restrict rc, unsigned long* restrict* restrict img) +{ + unsigned long x, y, e, rgb; + unsigned long a1, r1, g1, b1, a2, r2, g2, b2; + for (y = 0; y < HEIGHT; y++) + for (x = 0, e = 0; x < WIDTH; x++) + if (rc[x + e][y] = img[x][y], x % 3 == 2) + { + if (rgb = img[x][y], x < WIDTH - 1) + { + subpixels(rgb, &a1, &r1, &g1, &b1); + subpixels(img[x + 1][y], &a2, &r2, &g2, &b2); + r1 = ((r1 + r2) / 2) << 16; + g1 = ((g1 + g2) / 2) << 8; + b1 = ((b1 + b2) / 2) << 0; + rgb = r1 | g1 | b1; + } + rc[x + ++e][y] = rgb; + } +} + + +static unsigned long* restrict* make_buffer(unsigned long n, unsigned long m) +{ + unsigned long i; + unsigned long* restrict* restrict rc = malloc(n * sizeof(unsigned long*)); + for (i = 0; i < n; i++) + rc[i] = calloc(m, sizeof(unsigned long)); + return rc; +} + + +static void free_buffer(unsigned long* restrict* restrict buffer, unsigned long n) +{ + unsigned long i; + for (i = 0; i < n; i++) + free(buffer[i]); +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wcast-qual" + free((unsigned long**)buffer); +# pragma GCC diagnostic pop +} + + +static unsigned long* restrict* load_p6(const char* restrict filename) +{ + unsigned char* restrict data = malloc((size_t)(WIDTH * HEIGHT * 3) * sizeof(unsigned char)); + unsigned long* restrict* restrict rc = make_buffer(WIDTH, HEIGHT); + unsigned long y, x, p = 0; + ssize_t got; + int fd; + + fd = open(filename, O_RDONLY); + while (p < (unsigned long)(WIDTH * HEIGHT * 3)) + { + got = read(fd, data + p, ((unsigned long)(WIDTH * HEIGHT * 3) - p) * sizeof(char)); + if (got <= 0) + if ((got == 0) || (errno != EINTR)) + abort(); + if (got > 0) + p += (unsigned long)got; + } + close(fd); + + for (y = 0; y < HEIGHT; y++) + for (x = 0; x < WIDTH; x++) + { + unsigned long r = (unsigned long)(*data++); + unsigned long g = (unsigned long)(*data++); + unsigned long b = (unsigned long)(*data++); + rc[x][y] = (r << 16) | (g << 8) | b; + } + + free(data - WIDTH * HEIGHT * 3); + return rc; +} + + +static char* next_line(void) +{ + static char buf[512]; + unsigned long ptr = 0; + char c; + while (c = (char)getchar(), c != '\n') + buf[ptr++] = c; + buf[ptr] = '\0'; + return buf; +} + + +int main(int argc, char** argv) +{ + unsigned long y, x, i, n, ci, yi, xi, offx, offy, width, height; + unsigned long back = 0, fore = 0, chars, chary, charx; + unsigned long long foreback = 0; + unsigned long* restrict chr; + char* restrict line; + unsigned long* restrict* restrict charmap; + char* restrict splash_filename; + unsigned long* restrict* restrict splash; + unsigned long* restrict* restrict background; + unsigned long* restrict* restrict foreground; + unsigned long* restrict* restrict shadow; + char** restrict rows; + + /* Read image data. */ + splash_filename = strdup(next_line()); + width = (unsigned long)atol(next_line()); + height = (unsigned long)atol(next_line()); + rows = malloc(height * sizeof(char*)); + for (i = 0; i < height; i++) + rows[i] = strdup(next_line()); + + /* Read font data. */ + chars = (unsigned long)atol(next_line()); + charx = (unsigned long)atol(next_line()); + chary = (unsigned long)atol(next_line()); + charmap = malloc(chars * sizeof(unsigned long*)); + for (i = 0; i < chars; i++) + { + charmap[i] = calloc(chary, sizeof(unsigned long)); + for (y = 0; y < chary; y++) + for (line = next_line(), x = 0; x < charx; x++) + charmap[i][y] |= (line[x] == ' ' ? 0UL : 1UL) << x; + } + + /* The overlay should be centered on the background. */ + offx = (WIDTH - width * charx) / 2; + offy = (HEIGHT - height * chary) / 2; + + /* Buffers for layers. */ + splash = load_p6(splash_filename); + background = make_buffer(width * charx, height * chary); + foreground = make_buffer(width * charx, height * chary); + shadow = make_buffer(width * charx, height * chary); + free(splash_filename); + + /* Fill largers. */ + for (y = 0; y < height; y++) + { + char* restrict row = rows[y]; + char escape = 0; + for (i = 0, x = 0, n = strlen(row); i < n; i++) + { + char c = row[i]; + if (c == '\033') + { + fore = (unsigned long)(foreback >> 32); + back = (unsigned long)(foreback & ((1LL << 32) - 1LL)); + escape ^= 1; + foreback = 0; + } + else if (escape) + { + if (c == '#') + continue; + foreback <<= 4; + foreback |= (unsigned long long)((c & 15) + (c <= '9' ? 0 : 9)); + } + else + { + if (ci = (unsigned long)(unsigned char)c % chars, c & 0x80) + { + char* restrict s = row + i; + i += 2; + if (strstr(s, "┌") == s) ci = 218; + else if (strstr(s, "─") == s) ci = 196; + else if (strstr(s, "┐") == s) ci = 191; + else if (strstr(s, "│") == s) ci = 179; + else if (strstr(s, "├") == s) ci = 195; + else if (strstr(s, "┤") == s) ci = 180; + else if (strstr(s, "└") == s) ci = 192; + else if (strstr(s, "┘") == s) ci = 217; + else + i -= 2; + } + chr = charmap[ci]; + for (yi = 0; yi < chary; yi++) + for (xi = 0; xi < charx; xi++) + { + unsigned long xo = (chr[yi] >> xi) & 1; + unsigned long t = offx + x * charx + xi + xo; + unsigned long rgb = splash[t < WIDTH ? t : (WIDTH - 1)][offy + y * chary + yi]; + unsigned long _a, r, g, b, ca, cr, cg, cb, c_; + unsigned long* restrict* restrict i_; + subpixels(rgb, &_a, &r, &g, &b); + if (xo) + shadow[x * charx + xi][y * chary + yi] = 128UL << 24; + c_ = xo == 1 ? fore : back; + i_ = xo == 1 ? foreground : background; + subpixels(c_, &ca, &cr, &cg, &cb); + r = join(cr, r, ca); + g = join(cg, g, ca); + b = join(cb, b, ca); + rgb = (255UL << 24) | (r << 16) | (g << 8) | b; + i_[x * charx + xi][y * chary + yi] = rgb; + (void) _a; + } + x++; + } + } + } + + /* Apply layers. */ + width *= charx; + buffer_join(background, splash, width, height * chary, offx, offy); + buffer_join(shadow, splash, width, height * chary, offx, offy); + buffer_join(foreground, splash, width, height * chary, offx, offy); + + free_buffer(background, width); + free_buffer(foreground, width); + free_buffer(shadow, width); + + /* Make widescreen preview. */ + if (strchr(argv[2], 'W')) + *strchr(argv[2], 'W') = 'w'; + if ((strstr(argv[2], "-w") == argv[2]) || (strstr(argv[2], "--w") == argv[2])) + { + unsigned long* restrict* restrict original = splash; + width = HEIGHT * 16 / 9; + splash = make_buffer(width, HEIGHT); + widescreen(splash, original); + free_buffer(original, WIDTH); + } + else + width = WIDTH; + + /* Print image. */ + printf("P6\n%lu %i\n255\n", width, HEIGHT); + for (y = 0; y < HEIGHT; y++) + for (x = 0; x < width; x++) + { + unsigned long _a, r, g, b; + subpixels(splash[x][y], &_a, &r, &g, &b); + putchar_unlocked((int)r); + putchar_unlocked((int)g); + putchar_unlocked((int)b); + } + fflush(stdout); + + for (i = 0; i < height; i++) + free(rows[i]); + free(rows); + free_buffer(charmap, chars); + free_buffer(splash, width); + return 0; + (void) argc; +} + diff --git a/src/splashtool b/src/splashtool index 8135456..0791b66 100755 --- a/src/splashtool +++ b/src/splashtool @@ -20,6 +20,7 @@ in="$(realpath "${1}")" out="$(realpath "${2}")" +export wide="${3}" d="$(dirname "$(realpath "${0}")")" @@ -31,7 +32,7 @@ cd "$(dirname "${1}")" make_image () { if [ -z "${debug}" ]; then - "${d}/assemble" "${out}" "${3}" | convert /dev/stdin "${out}" + "${d}/assemble" "${out}" "${wide}" | convert /dev/stdin "${out}" else cat fi @@ -146,6 +147,7 @@ export border="$(csel color_border)" # Convert background image to binary portable anymap. background_file="$(mktemp /tmp/.tmp.XXXXXXXXXXXXXXXXXXXX.ppm)" convert "$(sel background)" "${background_file}" +sed -i 1,3d "${background_file}" # Make image. ( -- cgit v1.2.3-70-g09d2