aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile17
-rw-r--r--main.c98
-rw-r--r--pixelsort.c125
-rw-r--r--pixelsort.h37
-rw-r--r--sort.c47
-rw-r--r--sort.h13
6 files changed, 337 insertions, 0 deletions
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..1483e96
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,17 @@
+CC=gcc
+
+LFLAGS=-lfreeimage
+CFLAGS=-ggdb -O3 -Wall
+
+CFILES = $(wildcard *.c)
+
+pixelsort: $(CFILES)
+ $(CC) $(CFLAGS) $(LFLAGS) -o $@ $^
+
+.PHONY: run clean
+
+run: pixelsort
+ ./pixelsort
+
+clean:
+ rm pixelsort
diff --git a/main.c b/main.c
new file mode 100644
index 0000000..7c63836
--- /dev/null
+++ b/main.c
@@ -0,0 +1,98 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <FreeImage.h>
+
+#include "pixelsort.h"
+
+void printhelp(char *executable) {
+ printf("usage: %s [options]\n", executable);
+ printf("\n");
+ printf("options:\n");
+ printf(" -h this help message.\n");
+ printf(" -u threshold upper limit (default: 204).\n");
+ printf(" -l threshold lower limit (default: 63).\n");
+ printf(" -d order of sorting directions (default \"hv\").\n");
+}
+
+void parseargs(int argc, char **argv, context_t *ctx) {
+ int opt;
+
+ while((opt = getopt(argc, argv, "hd:u:l:")) != -1) {
+ switch (opt) {
+ case 'u':
+ ctx->upper = strtol(optarg, NULL, 10);
+ break;
+ case 'l':
+ ctx->lower = strtol(optarg, NULL, 10);
+ break;
+ case 'd':
+ ctx->dirs = optarg;
+ break;
+ case 'h':
+ printhelp(argv[0]);
+ exit(0);
+ break;
+ case '?':
+ printhelp(argv[0]);
+ exit(1);
+ break;
+ }
+ }
+
+}
+
+FIBITMAP *load_image(char *name) {
+ FREE_IMAGE_FORMAT imgformat = FreeImage_GetFileType(name, 0);
+ if (imgformat == FIF_UNKNOWN) {
+ fprintf(stderr, "Could not determine image format\n");
+ return NULL;
+ }
+
+ FIBITMAP *temp = FreeImage_Load(imgformat, name, 0);
+ if (!temp) {
+ fprintf(stderr, "Error loading image\n");
+ return NULL;
+ }
+
+ FIBITMAP *image = FreeImage_ConvertTo24Bits(temp);
+ if (!temp) {
+ fprintf(stderr, "Error converting image to 24 bits\n");
+ return NULL;
+ }
+
+ FreeImage_Unload(temp);
+
+ return image;
+}
+
+int main(int argc, char **argv) {
+ context_t ctx = {
+ .upper = 204,
+ .lower = 63,
+ .dirs = "hv",
+ .check_color = checkThreshold
+ };
+ parseargs(argc, argv, &ctx);
+
+ printf("Starting\n");
+ FreeImage_Initialise(1);
+
+ FIBITMAP *img = load_image("test.png");
+ if (!img) {
+ fprintf(stderr, "Error loading image test.png\n");
+ return 1;
+ }
+
+ int ret = pixelsort(&ctx, img);
+ if (ret) {
+ exit(1);
+ }
+
+ if (!FreeImage_Save(FIF_PNG, img, "test2.png", 0)) {
+ fprintf(stderr, "Error saving to test2.png\n");
+ return 1;
+ }
+
+ FreeImage_DeInitialise();
+}
diff --git a/pixelsort.c b/pixelsort.c
new file mode 100644
index 0000000..4a99f90
--- /dev/null
+++ b/pixelsort.c
@@ -0,0 +1,125 @@
+#include "pixelsort.h"
+
+#include <stdio.h>
+#include <FreeImage.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "sort.h"
+
+#define SUM(c) (c[FI_RGBA_RED] + c[FI_RGBA_GREEN] + c[FI_RGBA_BLUE])
+#define SCALEUP(c) (255 * c)
+
+int maxcomp(BYTE *c) {
+ int first = (c[FI_RGBA_RED] < c[FI_RGBA_BLUE]) ?
+ c[FI_RGBA_BLUE] : c[FI_RGBA_RED];
+ return (first < c[FI_RGBA_GREEN]) ? c[FI_RGBA_GREEN] : first;
+}
+
+bool checkThreshold(struct context *ctx, BYTE *color) {
+ int light = maxcomp(color);
+ return light >= ctx->lower && light <= ctx->upper;
+}
+
+BYTE *indexcolor_horizontal(struct context *ctx, BYTE *line, unsigned index) {
+ return line + BPP * index;
+}
+
+BYTE *indexcolor_vertical(struct context *ctx, BYTE *line, unsigned index) {
+ return line + BPP * index * ctx->width;
+}
+
+void sortpart(context_t *ctx, BYTE *part, pixelm *values, unsigned length) {
+ quicksort(values, 0, length-1);
+
+ BYTE *color;;
+ for (unsigned i = 0; i < length; i++) {
+ color = ctx->index_color(ctx, part, i);
+ memcpy(color, values[i].color, 3);
+ }
+}
+
+
+int sortline(context_t *ctx, BYTE *line, unsigned length) {
+ int start = -1;
+ pixelm *pixelvalues = (pixelm *) malloc(length * sizeof(pixelm));
+ if (!pixelvalues) {
+ fprintf(stderr, "Could not allocate array\n");
+ return 1;
+ }
+ unsigned pxindex = 0;
+
+ BYTE *color;;
+ for (unsigned i = 0; i < length; i++) {
+ color = ctx->index_color(ctx, line, i);
+
+ int light = maxcomp(color);
+ if (ctx->check_color(ctx, color)) {
+ if (start < 0) {
+ start = i;
+ pxindex = 0;
+ }
+ // Reserve sorting to make bleedlines go "down"
+ pixelvalues[pxindex].val = ctx->angle == ANGLE_VERT ? -light : light;
+ memcpy(pixelvalues[pxindex].color, color, 3);
+ pxindex++;
+ } else if (start >= 0) {
+ sortpart(ctx, ctx->index_color(ctx, line, start), pixelvalues, pxindex);
+ //qsort((void *)&line[start * 3], i - start - 1, 3, compare);
+
+ start = -1;
+ }
+ }
+
+ if (start >= 0) {
+ //qsort((void *)&line[start * 3], length - start - 1, 3, compare);
+ sortpart(ctx, ctx->index_color(ctx, line, start), pixelvalues, pxindex);
+ }
+
+ free(pixelvalues);
+
+ return 0;
+}
+
+void pixelsort_single(context_t *ctx, FIBITMAP *img) {
+ unsigned length = ctx->angle == ANGLE_VERT ? ctx->height : ctx->width;
+ unsigned looptimes = ctx->angle == ANGLE_VERT ? ctx->width : ctx->height;
+
+ BYTE *bits = FreeImage_GetBits(img);
+
+ for (unsigned i = 0; i < looptimes; i++) {
+ BYTE *line = ctx->angle == ANGLE_HORI ?
+ indexcolor_vertical(ctx, bits, i) :
+ indexcolor_horizontal(ctx, bits, i);
+
+ sortline(ctx, line, length);
+ }
+}
+
+int pixelsort(context_t *ctx, FIBITMAP *img) {
+ ctx->width = FreeImage_GetWidth(img);
+ ctx->height = FreeImage_GetHeight(img);
+
+ char *dirs = ctx->dirs;
+
+ char c;
+ while ((c = *dirs++) != 0) {
+ switch (c) {
+ case 'v':
+ ctx->angle = ANGLE_VERT;
+ ctx->index_color = indexcolor_vertical;
+ break;
+ case 'h':
+ ctx->angle = ANGLE_HORI;
+ ctx->index_color = indexcolor_horizontal;
+ break;
+ default:
+ fprintf(stderr, "Invalid direction %c\n", c);
+ return 1;
+ }
+
+ pixelsort_single(ctx, img);
+ }
+
+ return 0;
+}
diff --git a/pixelsort.h b/pixelsort.h
new file mode 100644
index 0000000..4e6dcd0
--- /dev/null
+++ b/pixelsort.h
@@ -0,0 +1,37 @@
+#ifndef PXLSORT_H
+#define PXLSORT_H
+
+#include <FreeImage.h>
+#include <stdbool.h>
+
+#define BPP 3
+#define ANGLE_HORI 0
+#define ANGLE_VERT 90
+
+typedef struct context {
+ // Image variables
+ unsigned width;
+ unsigned height;
+
+ unsigned angle;
+
+ // Threshold variables
+ int upper;
+ int lower;
+ char *dirs;
+
+ // Functions
+ bool (*check_color)(struct context *ctx, BYTE *line);
+ BYTE *(*index_color)(struct context *ctx, BYTE *line, unsigned index);
+} context_t;
+
+// Interval functions
+bool checkThreshold(struct context *ctx, BYTE *color);
+
+// Nextcolor functions
+BYTE *indexcolor_horizontal(struct context *ctx, BYTE *line, unsigned index);
+BYTE *indexcolor_vertical(struct context *ctx, BYTE *line, unsigned index);
+
+int pixelsort(context_t *ctx, FIBITMAP *img);
+
+#endif
diff --git a/sort.c b/sort.c
new file mode 100644
index 0000000..b215b31
--- /dev/null
+++ b/sort.c
@@ -0,0 +1,47 @@
+#include "sort.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+
+#define SUM(c) (c[FI_RGBA_RED] + c[FI_RGBA_GREEN] + c[FI_RGBA_BLUE])
+
+unsigned partition(pixelm *arr, unsigned lo, unsigned hi) {
+ int pivot = arr[lo].val;
+ int i = lo - 1;
+ int j = hi + 1;
+
+ while (true) {
+ do {
+ i++;
+ } while (arr[i].val < pivot);
+
+ do {
+ j--;
+ } while (arr[j].val > pivot);
+
+ if (i >= j) {
+ return j;
+ }
+
+ // Swap j and i
+ pixelm temp;
+ memcpy(&temp, arr+i, sizeof(pixelm));
+ memcpy(arr+i, arr+j, sizeof(pixelm));
+ memcpy(arr+j, &temp, sizeof(pixelm));
+ }
+}
+
+void quicksort(pixelm *arr, unsigned lo, unsigned hi) {
+ if (lo >= hi) {
+ return;
+ }
+
+ unsigned p = partition(arr, lo, hi);
+ quicksort(arr, lo, p);
+ quicksort(arr, p+1, hi);
+
+ return;
+}
+
diff --git a/sort.h b/sort.h
new file mode 100644
index 0000000..651406d
--- /dev/null
+++ b/sort.h
@@ -0,0 +1,13 @@
+#ifndef SORT_H
+#define SORT_H
+
+#include <FreeImage.h>
+
+typedef struct {
+ uint8_t color[3];
+ uint16_t val;
+} pixelm;
+
+void quicksort(pixelm *arr, unsigned lo, unsigned hi);
+
+#endif