Skip to content

Instantly share code, notes, and snippets.

@vurtun
Last active March 16, 2019 20:58
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save vurtun/7797c879572ac5eefba409820fa8bd43 to your computer and use it in GitHub Desktop.
Save vurtun/7797c879572ac5eefba409820fa8bd43 to your computer and use it in GitHub Desktop.
Image processing
#define min(a,b) ((a) < (b) ? (a) : (b))
#define max(a,b) ((a) > (b) ? (a) : (b))
struct img {
size_t w, h;
size_t area;
size_t size;
unsigned char buf[];
};
static struct img*
img_new(size_t w, size_t h)
{
const size_t size = sizeof(struct img) + w * h * 3;
struct img *img = mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0);
img->w = w, img->h = h;
img->area = img->w * img->h;
img->size = img->area * 3;
return img;
}
static void
img_del(struct img *img)
{
if (!img) return;
munmap(img, sizeof(struct img) + img->w * img->h * 3);
}
static void
img_write(FILE *fp, const struct img *img)
{
fprintf(fp, "P6\n%zu %zu\n255\n", img->w, img->h);
fwrite(img->buf, img->area, 3, fp);
fflush(fp);
}
static struct img*
img_resize(struct img *img, size_t w, size_t h)
{
if (!img || img->w != w || img->h != h) {
img_del(img);
img = img_new(w,h);
}
return img;
}
static struct img*
img_read(struct img *img, FILE *fp)
{
size_t w, h;
if (fscanf(fp, "P6 %zu %zu%*d%*c", &w, &h) < 2) {
img_del(img);
return 0;
}
img = img_resize(img, w, h);
fread(img->buf, img->area, 3, fp);
return img;
}
static void
img_get(unsigned char *col, const struct img *img, size_t x, size_t y)
{
col[0] = img->buf[y * img->w * 3 + x * 3 + 0];
col[1] = img->buf[y * img->w * 3 + x * 3 + 1];
col[2] = img->buf[y * img->w * 3 + x * 3 + 2];
}
static void
img_set(struct img *img, size_t x, size_t y, const unsigned char *col)
{
img->buf[y * img->w * 3 + x * 3 + 0] = col[0];
img->buf[y * img->w * 3 + x * 3 + 1] = col[1];
img->buf[y * img->w * 3 + x * 3 + 2] = col[2];
}
static void
join(void)
{
pid_t wpid;
int status = 0;
while ((wpid = wait(&status)) > 0);
}
#define _GNU_SOURCE
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/wait.h>
#include <unistd.h>
#include "com.c"
static void
diff(struct img *d, const struct img *a, const struct img *b)
{
const size_t ncores = (size_t)sysconf(_SC_NPROCESSORS_ONLN);
size_t chunk = (d->area / ncores) + 1;
for (size_t j = 0, at = 0; j < ncores && at < d->area; ++j) {
const size_t s = min(at, d->area);
const size_t e = min(s + chunk, d->area);
const int pid = fork();
if (pid < 0) exit(errno);
if (pid == 0) {
for (size_t k = s; k < e; ++k) {
const size_t x = k % d->w;
const size_t y = k / d->w;
unsigned char ac[3];
unsigned char bc[3];
img_get(ac, a, x, y);
img_get(bc, b, x, y);
if (ac[0] != bc[0] || ac[1] != bc[1] || ac[2] != bc[2]) {
static const unsigned char white[3] = {255,255,255};
img_set(d, x,y, white);
} else {
static const unsigned char black[3] = {0,0,0};
img_set(d, x,y, black);
}
}
exit(EXIT_SUCCESS);
}
at += e - s;
}
join();
}
int main(void)
{
struct img *a = img_read(0, stdin);
struct img *b = img_read(0, stdin);
while (a && b) {
struct img *d = img_resize(0, min(a->w, b->w), min(a->h, b->h));
diff(d, a, b);
// img_write(stdout, a);
// img_write(stdout, b);
img_write(stdout, d);
img_del(d);
a = img_read(a, stdin);
b = img_read(b, stdin);
}
img_del(a);
img_del(b);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#define unused(a) ((void)a)
#define cast(t,p) ((t)(p))
#define cntof(a) ((int)(sizeof(a)/sizeof((a)[0])))
enum pipes {PIPE_READ, PIPE_WRITE, PIPE_CNT};
static int
proc(int *fp, char **args, int argc)
{
int pid = 0;
long res = pipe(fp);
unused(argc);
if (res < 0)
return -errno;
if (!(pid = fork())) {
dup2(fp[PIPE_WRITE], STDOUT_FILENO);
dup2(fp[PIPE_READ], STDIN_FILENO);
close(fp[PIPE_READ]);
close(fp[PIPE_WRITE]);
if (args[0] != 0)
execvp(args[0], args);
fprintf(stderr, "kaon: execvp %s\n", args[0]);
perror(" failed\n");
exit(EXIT_FAILURE);
} else if (pid < 0)
return -errno;
else return pid;
}
enum img_col_comp {
IMG_COMP_RGBA,
IMG_COMP_ABGR,
IMG_COMP_BGRA
};
static int
img_write(const char *path, const void *mem, int w, int h, enum img_col_comp comp)
{
static const char *comps[] = {"rgba", "abgr", "bgra"};
char *args[16] = {0};
int fd[2] = {-1,-1};
int res = 0;
char dim[256];
snprintf(dim, sizeof(dim), "%dx%d", w, h);
args[0] = "ffmpeg";
args[1] = "-loglevel";
args[2] = "quiet";
args[3] = "-y";
args[4] = "-s";
args[5] = dim;
args[6] = "-f";
args[7] = "rawvideo";
args[8] = "-pixel_format";
args[9] = comps[comp];
args[10] = "-i";
args[11] = "pipe:0";
args[12] = "-vframes";
args[13] = "1";
args[14] = path;
res = proc(fd, args, cntof(args));
write(fd[PIPE_WRITE], mem, cast(size_t,(w*h*4)));
close(fd[PIPE_READ]);
close(fd[PIPE_WRITE]);
return res;
}
int main(void)
{
int res = 0;
int pid = img_write("image.png", img, w, h, IMG_COMP_RGBA);
waitpid(pid, &res, 0);
if (res == 0)
printf("Success\n");
else printf("Failed\n");
return 0;
}
#define _GNU_SOURCE
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/wait.h>
#include <unistd.h>
#include "com.c"
static void
grayscale(struct img *o, const struct img *i)
{
const size_t ncores = (size_t)sysconf(_SC_NPROCESSORS_ONLN);
size_t chunk = (i->area / ncores) + 1;
for (size_t j = 0, at = 0; j < ncores && at < i->area; ++j) {
const size_t b = min(at, i->area);
const size_t e = min(b + chunk, i->area);
const int pid = fork();
if (pid < 0) exit(errno);
if (pid == 0) {
for (size_t k = b; k < e; ++k) {
const size_t x = k % i->w;
const size_t y = k / i->w;
unsigned char c[3];
img_get(c, i, x, y);
unsigned char g = (c[0] + c[1] + c[2]) / 3;
c[0] = g, c[1] = g, c[2] = g;
img_set(o, x, y, c);
}
exit(EXIT_SUCCESS);
}
at += e - b;
}
join();
}
int main(int argc, char **argv)
{
FILE *fin = 0;
if (argc > 1) {
fin = fopen(argv[1], "r");
if (!fin) return 1;
} else fin = stdin;
struct img *o = 0;
struct img *i = img_read(0, fin);
while (i) {
o = img_resize(o, i->w, i->h);
grayscale(o, i);
img_write(stdout, o);
i = img_read(i, fin);
}
img_del(i);
img_del(o);
if (argc > 1)
fclose(fin);
return 0;
}
#define _GNU_SOURCE
#include <errno.h>
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/wait.h>
#include <unistd.h>
#include "com.c"
static size_t
floori(float x)
{
x = (float)((size_t)x) - ((x < 0.0f) ? 1 : 0);
return (size_t)x;
}
static void
nearest_scale(struct img *d, const struct img *i, size_t w, size_t h)
{
const size_t ncores = (size_t)sysconf(_SC_NPROCESSORS_ONLN);
const size_t chunk = (d->area / ncores) + 1;
const float x_ratio = (float)i->w / (float)w;
const float y_ratio = (float)i->h / (float)h;
for (size_t j = 0, at = 0; j < ncores && at < d->area; ++j) {
const size_t s = min(at, d->area);
const size_t e = min(s + chunk, d->area);
const int pid = fork();
if (pid < 0) exit(errno);
if (pid == 0) {
for (size_t k = s; k < e; ++k) {
const size_t dx = k % d->w;
const size_t dy = k / d->w;
const size_t sx = floori(dx * x_ratio);
const size_t sy = floori(dy * y_ratio);
unsigned char c[3];
img_get(c, i, sx, sy);
img_set(d, dx, dy, c);
}
exit(EXIT_SUCCESS);
}
at += e - s;
}
join();
}
static void
panic(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
vfprintf(stderr, fmt, args);
fprintf(stderr, "\n");
va_end(args);
exit(1);
}
static size_t
estrtol(const char *str)
{
char *ep = NULL;
long n = strtol(str, &ep, 10);
if (*ep != '\0' || ep == str)
panic("Invalid number: %s\n", str);
return (size_t)n;
}
int main(int argc, char **argv)
{
FILE *fin = 0;
if (argc > 3) {
fin = fopen(argv[3], "r");
if (!fin) return 1;
} else fin = stdin;
if (argc < 3)
panic("missing arguments\n");
const size_t w = estrtol(argv[1]);
const size_t h = estrtol(argv[2]);
struct img *o = 0;
struct img *i = img_read(0, fin);
while (i) {
o = img_resize(o, w, h);
nearest_scale(o, i, w, h);
img_write(stdout, o);
i = img_read(i, fin);
}
img_del(i);
img_del(o);
if (argc > 1)
fclose(fin);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment