Created
February 24, 2016 23:02
-
-
Save thejefflarson/9c104d39b6e04fdd5ef5 to your computer and use it in GitHub Desktop.
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 <fcntl.h> | |
#include <stdbool.h> | |
#include <stdlib.h> | |
#include <stdio.h> | |
#include <stdint.h> | |
#include <sys/select.h> | |
#include <sys/types.h> | |
#include <unistd.h> | |
#include <png.h> | |
static unsigned int component(png_const_bytep row, png_uint_32 x, | |
unsigned int c, unsigned int bit_depth, | |
unsigned int channels) { | |
png_uint_32 bit_offset_hi = bit_depth * ((x >> 6) * channels); | |
png_uint_32 bit_offset_lo = bit_depth * ((x & 0x3f) * channels + c); | |
row = (png_const_bytep)(((PNG_CONST png_byte(*)[8])row) + bit_offset_hi); | |
row += bit_offset_lo >> 3; | |
bit_offset_lo &= 0x07; | |
switch (bit_depth) { | |
case 1: | |
return (row[0] >> (7 - bit_offset_lo)) & 0x01; | |
case 2: | |
return (row[0] >> (6 - bit_offset_lo)) & 0x03; | |
case 4: | |
return (row[0] >> (4 - bit_offset_lo)) & 0x0f; | |
case 8: | |
return row[0]; | |
case 16: | |
return (row[0] << 8) + row[1]; | |
default: | |
fprintf(stderr, "pngpixel: invalid bit depth %u\n", bit_depth); | |
exit(1); | |
} | |
} | |
static void parse_pixel(uint8_t pixel[4], png_structp png_ptr, png_infop info_ptr, | |
png_const_bytep row, png_uint_32 x) { | |
PNG_CONST unsigned int bit_depth = png_get_bit_depth(png_ptr, info_ptr); | |
switch (png_get_color_type(png_ptr, info_ptr)) { | |
case PNG_COLOR_TYPE_RGB: | |
pixel[0] = component(row, x, 0, bit_depth, 3); | |
pixel[1] = component(row, x, 1, bit_depth, 3); | |
pixel[2] = component(row, x, 2, bit_depth, 3); | |
pixel[3] = 255; | |
return; | |
case PNG_COLOR_TYPE_RGB_ALPHA: | |
pixel[0] = component(row, x, 0, bit_depth, 4); | |
pixel[1] = component(row, x, 1, bit_depth, 4); | |
pixel[2] = component(row, x, 2, bit_depth, 4); | |
pixel[3] = component(row, x, 3, bit_depth, 4); | |
return; | |
default: | |
png_error(png_ptr, "invalid color type"); | |
} | |
} | |
typedef struct { | |
long x; | |
long y; | |
int fd; | |
png_infop info_ptr; | |
png_structp png_ptr; | |
int rowbytes; | |
png_byte color_type; | |
bool quadrants; | |
int read; | |
jmp_buf jmp; | |
int passes; | |
uint8_t pixels[4][4]; | |
} png_ctx_t; | |
struct args { | |
long x; | |
long y; | |
char *filename; | |
uint8_t pixels[4][4]; | |
}; | |
void | |
info_callback(png_structp png_ptr, png_infop info_ptr) { | |
png_uint_32 height, width; | |
int color_type, bit_depth; | |
png_ctx_t *ctx = png_get_progressive_ptr(png_ptr); | |
png_get_IHDR(png_ptr, info_ptr, &width, | |
&height, &bit_depth, &color_type, NULL, NULL, NULL); | |
png_read_update_info(ctx->png_ptr, ctx->info_ptr); | |
ctx->rowbytes = png_get_rowbytes(ctx->png_ptr, ctx->info_ptr); | |
ctx->passes = png_set_interlace_handling(png_ptr); | |
ctx->color_type = color_type; | |
ctx->info_ptr = info_ptr; | |
} | |
void | |
row_callback(png_structp png_ptr, png_bytep new_row, png_uint_32 row_num, int pass) { | |
png_ctx_t *ctx = png_get_progressive_ptr(png_ptr); | |
if(row_num == ctx->y) { | |
parse_pixel(ctx->pixels[0], png_ptr, ctx->info_ptr, new_row, ctx->x); | |
if(ctx->quadrants) | |
parse_pixel(ctx->pixels[1], png_ptr, ctx->info_ptr, new_row, ctx->x + 512); | |
ctx->read++; | |
} else if(row_num == ctx->y + 512 && ctx->quadrants) { | |
parse_pixel(ctx->pixels[2], png_ptr, ctx->info_ptr, new_row, ctx->x); | |
parse_pixel(ctx->pixels[3], png_ptr, ctx->info_ptr, new_row, ctx->x + 512); | |
ctx->read++; | |
} | |
} | |
void | |
error_handler(png_structp png_ptr, png_const_charp msg) { | |
fprintf(stderr, "readpng2 libpng error: %s\n", msg); | |
fflush(stderr); | |
png_ctx_t *ctx = png_get_error_ptr(png_ptr); | |
longjmp(ctx->jmp, 1); | |
} | |
// no error catching cuz yolo | |
int | |
ctx_init(png_ctx_t *ctx) { | |
ctx->png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, ctx, error_handler, NULL); | |
ctx->info_ptr = png_create_info_struct(ctx->png_ptr); | |
setjmp(ctx->jmp); | |
png_set_progressive_read_fn(ctx->png_ptr, ctx, info_callback, row_callback, NULL); | |
return 1; | |
} | |
int main(int argc, const char **argv) { | |
long x = atol(argv[1]); | |
long y = atol(argv[2]); | |
int j = 3; | |
png_ctx_t *contexts = calloc(argc - j, sizeof(png_ctx_t)); | |
for(int i = j; i < argc; i++) { | |
contexts[i - j].x = x; | |
contexts[i - j].y = y; | |
contexts[i - j].fd = open(argv[i], O_RDONLY | O_NONBLOCK); | |
if(contexts[i - j].fd == -1) { | |
fprintf(stderr, "could not open %s", argv[i]); | |
exit(1); | |
} | |
contexts[i - j].quadrants = (i != j); | |
ctx_init(&contexts[i - j]); | |
} | |
uint8_t buf[4096] = {0}; | |
while(1) { | |
fd_set set; | |
FD_ZERO(&set); | |
int maxfd = 0; | |
int numfds = 0; | |
for(int i = 0; i < argc - j; i++) { | |
if(contexts[i].read != 2) { | |
FD_SET(contexts[i].fd, &set); | |
if(contexts[i].fd > maxfd) | |
maxfd = contexts[i].fd; | |
numfds++; | |
} | |
} | |
if(numfds == 0) | |
break; | |
struct timeval tv; | |
tv.tv_sec = 0; | |
tv.tv_usec = 100; | |
select(maxfd + 1, &set, NULL, NULL, &tv); | |
for(int i = 0; i < argc - j; i++) { | |
if(FD_ISSET(contexts[i].fd, &set)) { | |
int rd = read(contexts[i].fd, buf, 4096); | |
if(rd > 0) { | |
setjmp(contexts[i].jmp); | |
png_process_data(contexts[i].png_ptr, contexts[i].info_ptr, buf, rd); | |
} else if(rd == 0) { | |
contexts[i].read = 2; | |
} | |
} | |
} | |
} | |
for(int i = j; i < argc; i++) { | |
png_ctx_t a = contexts[i-j]; | |
for(int j = 0; j < 4; j++) { | |
printf("%u %u %u %u\n", a.pixels[j][0], a.pixels[j][1], a.pixels[j][2], a.pixels[j][3]); | |
if(!a.quadrants) break; | |
} | |
} | |
free(contexts); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment