ff-utils

farbfeld tools and accessories
git clone git://nsmpr.xyz/ff-utils.git
Log | Files | Refs | README | LICENSE

ff-zoom.c (4483B)


      1 /*
      2  * this is modified version of farbfeld-resize
      3  * from https://github.com/ender672/farbfeld-resize
      4  */
      5 
      6 #include <arpa/inet.h>
      7 #include <stdint.h>
      8 #include <stdio.h>
      9 #include <stdlib.h>
     10 #include <string.h>
     11 
     12 struct image {
     13 	uint32_t width;
     14 	uint32_t height;
     15 	uint16_t *data;
     16 };
     17 
     18 struct header {
     19 	char sig[8];
     20 	uint32_t width;
     21 	uint32_t height;
     22 };
     23 
     24 void
     25 xscale(uint16_t *row_in, uint16_t *out, uint32_t width_in, uint32_t width_out,
     26 	uint32_t taps, uint32_t xpos)
     27 {
     28 	double x, tx, coeff, sum[4];
     29 	uint32_t i, j, smp_i, smp_safe;
     30 	int32_t val;
     31 
     32 	sum[0] = sum[1] = sum[2] = sum[3] = 0.0;
     33 	smp_i = (uint64_t)xpos * width_in / width_out;
     34 	tx = ((uint64_t)xpos * width_in % width_out) / (double)width_out;
     35 
     36 	for (i=1; i<=taps*2; i++) {
     37 		x = (i > taps ? i - taps - tx : taps - i + tx) / (taps / 2);
     38 		if (x < 1) {
     39 			coeff = (3*x*x*x - 5*x*x + 2) / taps;
     40 		} else {
     41 			coeff = (-1*x*x*x + 5*x*x - 8*x + 4) / taps;
     42 		}
     43 		smp_safe = smp_i + i < taps ? 0 : smp_i + i - taps;
     44 		smp_safe = smp_safe >= width_in ? width_in - 1 : smp_safe;
     45 		for (j=0; j<4; j++) {
     46 			sum[j] += row_in[smp_safe * 4 + j] / 65535.0 * coeff;
     47 		}
     48 	}
     49 
     50 	for (i=0; i<4; i++) {
     51 		val = 65535 * sum[i];
     52 		out[i] = val < 0 ? 0 : (val > 65535 ? 65535 : val);
     53 	}
     54 }
     55 
     56 void
     57 xscale_transpose(struct image in, struct image out)
     58 {
     59 	uint16_t *in_row, *out_smp;
     60 	uint32_t i, j, taps;
     61 
     62 	taps = out.height < in.width ? 2 * in.width / out.height : 2;
     63 	taps += taps & 1;
     64 
     65 	for (i=0; i<out.width; i++) {
     66 		in_row = in.data + i * in.width * 4;
     67 		for (j=0; j<out.height; j++) {
     68 			out_smp = out.data + (j * out.width + i) * 4;
     69 			xscale(in_row, out_smp, in.width, out.height, taps, j);
     70 		}
     71 	}
     72 }
     73 
     74 void
     75 crop(struct image in, struct image out)
     76 {
     77 	uint32_t i, j, dx, dy;
     78 	uint16_t *ip, *op;
     79 	dx = labs((in.width - out.width)/2);
     80 	dy = labs((in.height - out.height)/2);
     81 	
     82 	for (i=0; i<out.width; i++)
     83 		for (j=0; j<out.height; j++) {
     84 			ip = in.data + (i + dx + (j + dy) * in.width) * 4;
     85 			op = out.data + (i + j * out.width) * 4;
     86 			memcpy(op, ip, 8);
     87 		}
     88 }
     89 
     90 void*
     91 alloc_img(uint32_t width, uint32_t height)
     92 {
     93 	uint64_t tmp;
     94 	size_t size;
     95 
     96 	tmp = (uint64_t)width * height;
     97 	size = 4 * sizeof(uint16_t);
     98 
     99 	if (tmp > SIZE_MAX / size) {
    100 		return 0;
    101 	}
    102 	return malloc(tmp * size);
    103 }
    104 
    105 int
    106 main(int argc, char *argv[])
    107 {
    108 	struct header hdr;
    109 	struct image in, tmp, mid, out;
    110 	size_t i, in_len, out_len;
    111 	char *end;
    112 
    113 	if (argc != 3) {
    114 		fprintf(stderr, "usage: %s [width] [height]\n", argv[0]);
    115 		return 1;
    116 	}
    117 
    118 	out.width = strtoul(argv[1], &end, 10);
    119 	if (!end || !out.width) {
    120 		fprintf(stderr, "bad width given\n");
    121 		return 1;
    122 	}
    123 	out.height = strtoul(argv[2], &end, 10);
    124 	if (!end || !out.height) {
    125 		fprintf(stderr, "bad height given\n");
    126 		return 1;
    127 	}
    128 
    129 	mid.width = out.width;
    130 	mid.height = out.height;
    131 
    132 	if (fread(&hdr, 1, sizeof(hdr), stdin) != sizeof(hdr)) {
    133 		fprintf(stderr, "incomplete header\n");
    134 		return 1;
    135 	}
    136 	if (memcmp("farbfeld", hdr.sig, strlen("farbfeld"))) {
    137 		fprintf(stderr, "invalid magic\n");
    138 		return 1;
    139 	}
    140 	in.width = ntohl(hdr.width);
    141 	in.height = ntohl(hdr.height);
    142 	if (!in.width || !in.height) {
    143 		fprintf(stderr, "bad input image\n");
    144 		return 1;
    145 	}
    146 	
    147 	/* Fix the aspect ratio. */
    148 	if (mid.width / (double)in.width > mid.height / (double)in.height) {
    149 		mid.height = in.height * mid.width / in.width;
    150 		mid.height = mid.height ? mid.height : 1;
    151 	} else {
    152 		mid.width = in.width * mid.height / in.height;
    153 		mid.width = mid.width ? mid.width : 1;
    154 	}
    155 
    156 	hdr.width = htonl(out.width);
    157 	hdr.height = htonl(out.height);
    158 	if (fwrite(&hdr, sizeof(hdr), 1, stdout) != 1) {
    159 		fprintf(stderr, "unable to write header\n");
    160 		return 1;
    161 	}
    162 
    163 	tmp.width = in.height;
    164 	tmp.height = mid.width;
    165 
    166 	in_len = in.width * in.height * 4;
    167 	out_len = out.width * out.height * 4;
    168 
    169 	in.data = alloc_img(in.width, in.height);
    170 	mid.data = alloc_img(mid.width, mid.height);
    171 	out.data = alloc_img(out.width, out.height);
    172 	tmp.data = alloc_img(tmp.width, tmp.height);
    173 
    174 	if (!in.data || !out.data || !tmp.data) {
    175 		fprintf(stderr, "unable to allocate memory.\n");
    176 		return 1;
    177 	}
    178 
    179 	if (fread(in.data, sizeof(uint16_t), in_len, stdin) != in_len) {
    180 		fprintf(stderr, "unexpected EOF\n");
    181 		return 1;
    182 	}
    183 	for (i = 0; i < in_len; i++) {
    184 		in.data[i] = ntohs(in.data[i]);
    185 	}
    186 
    187 	xscale_transpose(in, tmp);
    188 	xscale_transpose(tmp, mid);
    189 	crop(mid, out);
    190 
    191 	for (i = 0; i < out_len; i++) {
    192 		out.data[i] = htons(out.data[i]);
    193 	}
    194 	if (fwrite(out.data, sizeof(uint16_t), out_len, stdout) != out_len) {
    195 		fprintf(stderr, "write error\n");
    196 		return 1;
    197 	}
    198 	return 0;
    199 }