aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMattias Andrée <maandree@operamail.com>2014-11-02 21:43:08 +0100
committerMattias Andrée <maandree@operamail.com>2014-11-02 21:43:08 +0100
commitcfa70ef92fed3307f7e4c04a41a284a3a1f95355 (patch)
tree3b5497741085135c1342342a08620342a12e6731 /src
parentm (diff)
downloadsplashtool-cfa70ef92fed3307f7e4c04a41a284a3a1f95355.tar.gz
splashtool-cfa70ef92fed3307f7e4c04a41a284a3a1f95355.tar.bz2
splashtool-cfa70ef92fed3307f7e4c04a41a284a3a1f95355.tar.xz
c for performance1414962500
Signed-off-by: Mattias Andrée <maandree@operamail.com>
Diffstat (limited to 'src')
-rwxr-xr-xsrc/assemble206
-rw-r--r--src/assemble.c332
-rwxr-xr-xsrc/splashtool4
3 files changed, 335 insertions, 207 deletions
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 <http://www.gnu.org/licenses/>.
-'''
-
-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 <http://www.gnu.org/licenses/>.
+ */
+#define _GNU_SOURCE
+#include <math.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+
+
+#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.
(