Last active
March 16, 2019 20:58
-
-
Save vurtun/7797c879572ac5eefba409820fa8bd43 to your computer and use it in GitHub Desktop.
Image processing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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