commit 5e166c098b589474090c8a9cc63e70c895606e57
parent a4d7abf14d9eb3465ab4f773e8a20e580e8c30cc
Author: prenev <an2qzavok@gmail.com>
Date: Sun, 21 Mar 2021 21:17:01 +0300
ff-zoom
Diffstat:
3 files changed, 208 insertions(+), 4 deletions(-)
diff --git a/Makefile b/Makefile
@@ -2,5 +2,7 @@ include config.mk
ff-pattern: ff-pattern.c
+ff-zoom: ff-zoom.c
+
clean:
- rm -f ff-pattern
+ rm -f ff-pattern ff-zoom
diff --git a/ff-pattern.c b/ff-pattern.c
@@ -6,8 +6,8 @@
#include <string.h>
int fid;
-long inx, iny, outx, outy;
-long size, i, x, y;
+long inx, iny, outx, outy;
+long size, n, i, x, y;
uint32_t hbuf[4];
char *buf;
char *argv0;
@@ -36,7 +36,10 @@ main(int argc, char **argv)
size = inx * iny * 8;
buf = malloc(size);
- read(fid, buf, size);
+ n = read(fid, buf, size);
+ if (n < size) {
+ fprintf(stderr, "underread\n");
+ }
hbuf[2] = htonl(outx);
hbuf[3] = htonl(outy);
write(1, hbuf, 16);
diff --git a/ff-zoom.c b/ff-zoom.c
@@ -0,0 +1,199 @@
+/*
+ * this is modified version of farbfeld-resize
+ * from https://github.com/ender672/farbfeld-resize
+ */
+
+#include <arpa/inet.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+struct image {
+ uint32_t width;
+ uint32_t height;
+ uint16_t *data;
+};
+
+struct header {
+ char sig[8];
+ uint32_t width;
+ uint32_t height;
+};
+
+void
+xscale(uint16_t *row_in, uint16_t *out, uint32_t width_in, uint32_t width_out,
+ uint32_t taps, uint32_t xpos)
+{
+ double x, tx, coeff, sum[4];
+ uint32_t i, j, smp_i, smp_safe;
+ int32_t val;
+
+ sum[0] = sum[1] = sum[2] = sum[3] = 0.0;
+ smp_i = (uint64_t)xpos * width_in / width_out;
+ tx = ((uint64_t)xpos * width_in % width_out) / (double)width_out;
+
+ for (i=1; i<=taps*2; i++) {
+ x = (i > taps ? i - taps - tx : taps - i + tx) / (taps / 2);
+ if (x < 1) {
+ coeff = (3*x*x*x - 5*x*x + 2) / taps;
+ } else {
+ coeff = (-1*x*x*x + 5*x*x - 8*x + 4) / taps;
+ }
+ smp_safe = smp_i + i < taps ? 0 : smp_i + i - taps;
+ smp_safe = smp_safe >= width_in ? width_in - 1 : smp_safe;
+ for (j=0; j<4; j++) {
+ sum[j] += row_in[smp_safe * 4 + j] / 65535.0 * coeff;
+ }
+ }
+
+ for (i=0; i<4; i++) {
+ val = 65535 * sum[i];
+ out[i] = val < 0 ? 0 : (val > 65535 ? 65535 : val);
+ }
+}
+
+void
+xscale_transpose(struct image in, struct image out)
+{
+ uint16_t *in_row, *out_smp;
+ uint32_t i, j, taps;
+
+ taps = out.height < in.width ? 2 * in.width / out.height : 2;
+ taps += taps & 1;
+
+ for (i=0; i<out.width; i++) {
+ in_row = in.data + i * in.width * 4;
+ for (j=0; j<out.height; j++) {
+ out_smp = out.data + (j * out.width + i) * 4;
+ xscale(in_row, out_smp, in.width, out.height, taps, j);
+ }
+ }
+}
+
+void
+crop(struct image in, struct image out)
+{
+ uint32_t i, j, dx, dy;
+ uint16_t *ip, *op;
+ dx = labs((in.width - out.width)/2);
+ dy = labs((in.height - out.height)/2);
+
+ for (i=0; i<out.width; i++)
+ for (j=0; j<out.height; j++) {
+ ip = in.data + (i + dx + (j + dy) * in.width) * 4;
+ op = out.data + (i + j * out.width) * 4;
+ memcpy(op, ip, 8);
+ }
+}
+
+void*
+alloc_img(uint32_t width, uint32_t height)
+{
+ uint64_t tmp;
+ size_t size;
+
+ tmp = (uint64_t)width * height;
+ size = 4 * sizeof(uint16_t);
+
+ if (tmp > SIZE_MAX / size) {
+ return 0;
+ }
+ return malloc(tmp * size);
+}
+
+int
+main(int argc, char *argv[])
+{
+ struct header hdr;
+ struct image in, tmp, mid, out;
+ size_t i, in_len, out_len;
+ char *end;
+
+ if (argc != 3) {
+ fprintf(stderr, "usage: %s [width] [height]\n", argv[0]);
+ return 1;
+ }
+
+ out.width = strtoul(argv[1], &end, 10);
+ if (!end || !out.width) {
+ fprintf(stderr, "bad width given\n");
+ return 1;
+ }
+ out.height = strtoul(argv[2], &end, 10);
+ if (!end || !out.height) {
+ fprintf(stderr, "bad height given\n");
+ return 1;
+ }
+
+ mid.width = out.width;
+ mid.height = out.height;
+
+ if (fread(&hdr, 1, sizeof(hdr), stdin) != sizeof(hdr)) {
+ fprintf(stderr, "incomplete header\n");
+ return 1;
+ }
+ if (memcmp("farbfeld", hdr.sig, strlen("farbfeld"))) {
+ fprintf(stderr, "invalid magic\n");
+ return 1;
+ }
+ in.width = ntohl(hdr.width);
+ in.height = ntohl(hdr.height);
+ if (!in.width || !in.height) {
+ fprintf(stderr, "bad input image\n");
+ return 1;
+ }
+
+ /* Fix the aspect ratio. */
+ if (mid.width / (double)in.width > mid.height / (double)in.height) {
+ mid.height = in.height * mid.width / in.width;
+ mid.height = mid.height ? mid.height : 1;
+ } else {
+ mid.width = in.width * mid.height / in.height;
+ mid.width = mid.width ? mid.width : 1;
+ }
+
+ hdr.width = htonl(out.width);
+ hdr.height = htonl(out.height);
+ if (fwrite(&hdr, sizeof(hdr), 1, stdout) != 1) {
+ fprintf(stderr, "unable to write header\n");
+ return 1;
+ }
+
+ tmp.width = in.height;
+ tmp.height = mid.width;
+
+ in_len = in.width * in.height * 4;
+ out_len = out.width * out.height * 4;
+
+ in.data = alloc_img(in.width, in.height);
+ mid.data = alloc_img(mid.width, mid.height);
+ out.data = alloc_img(out.width, out.height);
+ tmp.data = alloc_img(tmp.width, tmp.height);
+
+ if (!in.data || !out.data || !tmp.data) {
+ fprintf(stderr, "unable to allocate memory.\n");
+ return 1;
+ }
+
+ if (fread(in.data, sizeof(uint16_t), in_len, stdin) != in_len) {
+ fprintf(stderr, "unexpected EOF\n");
+ return 1;
+ }
+ for (i = 0; i < in_len; i++) {
+ in.data[i] = ntohs(in.data[i]);
+ }
+
+ xscale_transpose(in, tmp);
+ xscale_transpose(tmp, mid);
+ crop(mid, out);
+
+ for (i = 0; i < out_len; i++) {
+ out.data[i] = htons(out.data[i]);
+ }
+ if (fwrite(out.data, sizeof(uint16_t), out_len, stdout) != out_len) {
+ fprintf(stderr, "write error\n");
+ return 1;
+ }
+ return 0;
+}