Instantly share code, notes, and snippets.

Embed
What would you like to do?
#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