summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2010-01-13 11:25:53 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2010-01-13 11:25:53 -0800
commit7a7221a3b06882d314d4256d31cdf4a68c2f6b5d (patch)
tree066fe8942109996f600736e5491a085522173a65
downloadpesconvert-7a7221a3b06882d314d4256d31cdf4a68c2f6b5d.tar.gz
Initial PES conversion
Right now it just knows how to convert to SVG. Which isn't all that interesting, but the parsing logic comes from https://bugs.launchpad.net/inkscape/+bug/247463 which has a php script to do this, and it's all based on that.
-rw-r--r--.gitignore2
-rw-r--r--Makefile5
-rw-r--r--pes.c327
-rw-r--r--pes.h29
-rw-r--r--svg.c37
5 files changed, 400 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..9bee64a
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+pesconvert
+*.o
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..e2ebd02
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,5 @@
+CC=gcc
+CFLAGS=-Wall
+
+pesconvert: pes.o svg.o
+ $(CC) -o $@ $^
diff --git a/pes.c b/pes.c
new file mode 100644
index 0000000..7a9a0e9
--- /dev/null
+++ b/pes.c
@@ -0,0 +1,327 @@
+/*
+ * PES file parsing.
+ *
+ * All format credit goes to Robert Heel and
+ *
+ * https://bugs.launchpad.net/inkscape/+bug/247463
+ *
+ * which has a php script to do so. He in turn seems to have
+ * gotten it from NJ Crawford's C# PES viewer. I just turned
+ * it into C.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <string.h>
+
+#include "pes.h"
+
+static struct color color_def[256] = {
+ { NULL, 0, 0, 0 },
+ { "Color1", 14, 31, 124 },
+ { "Color2", 10, 85, 163 },
+ { "Color3", 48, 135, 119 },
+ { "Color4", 75, 107, 175 },
+ { "Color5", 237, 23, 31 },
+ { "Color6", 209, 92, 0 },
+ { "Color7", 145, 54, 151 },
+ { "Color8", 228, 154, 203 },
+ { "Color9", 145, 95, 172 },
+ { "Color10", 157, 214, 125 },
+ { "Color11", 232, 169, 0 },
+ { "Color12", 254, 186, 53 },
+ { "Color13", 255, 255, 0 },
+ { "Color14", 112, 188, 31 },
+ { "Color15", 192, 148, 0 },
+ { "Color16", 168, 168, 168 },
+ { "Color17", 123, 111, 0 },
+ { "Color18", 255, 255, 179 },
+ { "Color19", 79, 85, 86 },
+ { "Black", 0, 0, 0 },
+ { "Color21", 11, 61, 145 },
+ { "Color22", 119, 1, 118 },
+ { "Color23", 41, 49, 51 },
+ { "Color24", 42, 19, 1 },
+ { "Color25", 246, 74, 138 },
+ { "Color26", 178, 118, 36 },
+ { "Color27", 252, 187, 196 },
+ { "Color28", 254, 55, 15 },
+ { "White", 240, 240, 240 },
+ { "Color30", 106, 28, 138 },
+ { "Color31", 168, 221, 196 },
+ { "Color32", 37, 132, 187 },
+ { "Color33", 254, 179, 67 },
+ { "Color34", 255, 240, 141 },
+ { "Color35", 208, 166, 96 },
+ { "Color36", 209, 84, 0 },
+ { "Color37", 102, 186, 73 },
+ { "Color38", 19, 74, 70 },
+ { "Color39", 135, 135, 135 },
+ { "Color40", 216, 202, 198 },
+ { "Color41", 67, 86, 7 },
+ { "Color42", 254, 227, 197 },
+ { "Color43", 249, 147, 188 },
+ { "Color44", 0, 56, 34 },
+ { "Color45", 178, 175, 212 },
+ { "Color46", 104, 106, 176 },
+ { "Color47", 239, 227, 185 },
+ { "Color48", 247, 56, 102 },
+ { "Color49", 181, 76, 100 },
+ { "Color50", 19, 43, 26 },
+ { "Color51", 199, 1, 85 },
+ { "Color52", 254, 158, 50 },
+ { "Color53", 168, 222, 235 },
+ { "Color54", 0, 103, 26 },
+ { "Color55", 78, 41, 144 },
+ { "Color56", 47, 126, 32 },
+ { "Color57", 253, 217, 222 },
+ { "Color58", 255, 217, 17 },
+ { "Color59", 9, 91, 166 },
+ { "Color60", 240, 249, 112 },
+ { "Color61", 227, 243, 91 },
+ { "Color62", 255, 200, 100 },
+ { "Color63", 255, 200, 150 },
+ { "Color64", 255, 200, 200 },
+};
+
+static struct color *my_colors[256];
+
+struct region {
+ const void *ptr;
+ unsigned int size;
+};
+
+#define CHUNKSIZE (8192)
+
+static int read_file(int fd, struct region *region)
+{
+ int len = 0, done = 0;
+ char *buf = NULL;
+
+ for (;;) {
+ int space = len - done, ret;
+ if (!space) {
+ space = CHUNKSIZE;
+ len += space;
+ buf = realloc(buf, len);
+ }
+ ret = read(fd, buf + done, space);
+ if (ret > 0) {
+ done += ret;
+ continue;
+ }
+ if (!ret)
+ break;
+ if (errno == EINTR || errno == EAGAIN)
+ continue;
+ free(buf);
+ return -1;
+ }
+
+ /* "len+8" guarantees that there is some slop at the end */
+ region->ptr = realloc(buf, len+8);
+ region->size = len;
+ return 0;
+}
+
+static int read_path(const char *path, struct region *region)
+{
+ if (path) {
+ int fd = open(path, O_RDONLY);
+ if (fd > 0) {
+ int ret = read_file(fd, region);
+ int saved_errno = errno;
+ close(fd);
+ errno = saved_errno;
+ return ret;
+ }
+ return fd;
+ }
+ return read_file(0, region);
+}
+
+static void report(const char *fmt, va_list params)
+{
+ vfprintf(stderr, fmt, params);
+}
+
+static void die(const char *fmt, ...)
+{
+ va_list params;
+
+ va_start(params, fmt);
+ report(fmt, params);
+ va_end(params);
+ exit(1);
+}
+
+#define get_u8(buf, offset) (*(unsigned char *)((offset)+(const char *)(buf)))
+#define get_le32(buf, offset) (*(unsigned int *)((offset)+(const char *)(buf)))
+
+static int parse_pes_colors(struct region *region, unsigned int pec)
+{
+ const void *buf = region->ptr;
+ int nr_colors = get_u8(buf, pec+48) + 1;
+ int i;
+
+ for (i = 0; i < nr_colors; i++) {
+ struct color *color;
+ color = color_def + get_u8(buf, pec+49+i);
+ my_colors[i] = color;
+ }
+ return 0;
+}
+
+static struct pes_block *new_block(struct pes *pes)
+{
+ int size = sizeof(struct pes_block) + 64*sizeof(struct stitch);
+ struct pes_block *block = malloc(size);
+
+ if (block) {
+ memset(block, 0, size);
+ block->max_stitches = 64;
+
+ pes->last = block;
+ *pes->listp = block;
+ pes->listp = &block->next;
+ block->color = my_colors[pes->nr_colors++];
+ }
+ return block;
+}
+
+static int add_stitch(struct pes *pes, int x, int y)
+{
+ struct pes_block *block = pes->last;
+ int nr_stitches = block->nr_stitches;
+
+ if (x < pes->min_x)
+ pes->min_x = x;
+ if (x > pes->max_x)
+ pes->max_x = x;
+ if (y < pes->min_y)
+ pes->min_y = y;
+ if (y > pes->max_y)
+ pes->max_y = y;
+
+ if (block->max_stitches == nr_stitches) {
+ int new_stitches = (nr_stitches * 3) / 2 + 64;
+ int size = sizeof(struct pes_block) + new_stitches*sizeof(struct stitch);
+ block = realloc(block, size);
+ if (!block)
+ return -1;
+ block->max_stitches = new_stitches;
+ }
+ block->stitch[nr_stitches].x = x;
+ block->stitch[nr_stitches].y = y;
+ block->nr_stitches = nr_stitches+1;
+ return 0;
+}
+
+static int parse_pes_stitches(struct region *region, unsigned int pec, struct pes *pes)
+{
+ int oldx, oldy;
+ const unsigned char *buf = region->ptr, *p, *end;
+ struct pes_block *block;
+
+ p = buf + pec + 532;
+ end = buf + region->size;
+
+ oldx = oldy = 0;
+
+ block = new_block(pes);
+
+ while (p < end) {
+ int val1 = p[0], val2 = p[1];
+ p += 2;
+ if (val1 == 255 && !val2)
+ return 0;
+ if (val1 == 254 && val2 == 176) {
+ if (block->nr_stitches) {
+ block = new_block(pes);
+ if (!block)
+ return -1;
+ }
+ p++; /* Skip byte */
+ continue;
+ }
+
+ /* High bit set means 12-bit offset, otherwise 7-bit signed delta */
+ if (val1 & 0x80) {
+ val1 = ((val1 & 15) << 8) + val2;
+ /* Signed 12-bit arithmetic */
+ if (val1 & 2048)
+ val1 -= 4096;
+ val2 = *p++;
+ } else {
+ if (val1 & 64)
+ val1 -= 128;
+ }
+
+ if (val2 & 0x80) {
+ val2 = ((val2 & 15) << 8) + *p++;
+ /* Signed 12-bit arithmetic */
+ if (val2 & 2048)
+ val2 -= 4096;
+ } else {
+ if (val2 & 64)
+ val2 -= 128;
+ }
+
+ val1 += oldx;
+ val2 += oldy;
+
+ oldx = val1;
+ oldy = val2;
+
+ if (add_stitch(pes, val1, val2))
+ return -1;
+ }
+ return 0;
+}
+
+static int parse_pes(struct region *region, struct pes *pes)
+{
+ const void *buf = region->ptr;
+ unsigned int size = region->size;
+ unsigned int pec;
+
+ if (size < 48)
+ return -1;
+ if (memcmp(buf, "#PES", 4))
+ return -1;
+ pec = get_le32(buf, 8);
+ if (pec > region->size)
+ return -1;
+ if (pec + 532 >= size)
+ return -1;
+ if (parse_pes_colors(region, pec) < 0)
+ return -1;
+ return parse_pes_stitches(region, pec, pes);
+}
+
+int main(int argc, char **argv)
+{
+ struct region region;
+ struct pes pes = {
+ .min_x = 65535, .max_x = -65535,
+ .min_y = 65535, .max_y = -65535,
+ .blocks = NULL,
+ .last = NULL,
+ .listp = &pes.blocks,
+ };
+
+ if (read_path(argv[1], &region))
+ die("Unable to read file %s (%s)\n", argv[1]?argv[1]:"<stdin>", strerror(errno));
+
+ if (parse_pes(&region, &pes) < 0)
+ die("Unable to parse PES file\n");
+
+ output_svg(&pes);
+
+ return 0;
+}
diff --git a/pes.h b/pes.h
new file mode 100644
index 0000000..08110da
--- /dev/null
+++ b/pes.h
@@ -0,0 +1,29 @@
+#ifndef PES_H
+#define PES_H
+
+struct color {
+ const char *name;
+ unsigned char r,g,b;
+};
+
+struct stitch {
+ int x, y;
+};
+
+struct pes_block {
+ struct pes_block *next;
+ struct color *color;
+ int nr_stitches, max_stitches;
+ struct stitch stitch[];
+};
+
+struct pes {
+ int nr_colors;
+ int min_x, max_x, min_y, max_y;
+ struct pes_block *blocks, *last, **listp;
+};
+
+void output_svg(struct pes *pes);
+void output_png(struct pes *pes);
+
+#endif /* PES_H */
diff --git a/svg.c b/svg.c
new file mode 100644
index 0000000..c792716
--- /dev/null
+++ b/svg.c
@@ -0,0 +1,37 @@
+#include <stdio.h>
+#include "pes.h"
+
+void output_svg(struct pes *pes)
+{
+ struct pes_block *block = pes->blocks;
+
+ printf("<?xml version=\"1.0\"?>\n");
+ printf("<svg xmlns=\"http://www.w3.org/2000/svg\" "
+ "xlink=\"http://www.w3.org/1999/xlink\" "
+ "ev=\"http://www.w3.org/2001/xml-events\" "
+ "version=\"1.1\" "
+ "baseProfile=\"full\" "
+ "width=\"%d\" height=\"%d\">",
+ pes->max_x - pes->min_x,
+ pes->max_y - pes->min_y);
+
+ while (block) {
+ int i;
+ printf("<path stroke=\"#%02x%02x%02x\" fill=\"none\" d=\"M %d %d",
+ block->color->r,
+ block->color->g,
+ block->color->b,
+ block->stitch[0].x - pes->min_x,
+ block->stitch[0].y - pes->min_y);
+ for (i = 1; i < block->nr_stitches; i++)
+ printf(" L %d %d",
+ block->stitch[i].x - pes->min_x,
+ block->stitch[i].y - pes->min_y);
+ printf("\"/>");
+
+ block = block->next;
+ }
+ printf("</svg>\n");
+}
+
+