diff options
author | Julian T <julian@jtle.dk> | 2020-07-16 21:49:05 +0200 |
---|---|---|
committer | Julian T <julian@jtle.dk> | 2020-07-16 21:49:05 +0200 |
commit | 3a4b55c20ac040ace53aba5f2715b9c080bea17f (patch) | |
tree | 9acbfd74f93fc011329a40dd0a4dc5213fadec3e |
Initial working pixelsorter
-rw-r--r-- | Makefile | 17 | ||||
-rw-r--r-- | main.c | 98 | ||||
-rw-r--r-- | pixelsort.c | 125 | ||||
-rw-r--r-- | pixelsort.h | 37 | ||||
-rw-r--r-- | sort.c | 47 | ||||
-rw-r--r-- | sort.h | 13 |
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 @@ -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 @@ -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; +} + @@ -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 |