Files
2023-11-20 23:33:25 +11:00

106 lines
2.7 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <tiffio.h>
#include <webp/encode.h>
#include "utils.h"
#define BUF_SIZE 1024 * 16
int tiff_to_webp(int inputDesc, int outputDesc, int targetSize) {
#ifdef HAS_DEBUG
clock_t t;
t = clock();
#endif
int status = 0;
FILE* input = fdopen(inputDesc, "r");
FILE* output = fdopen(outputDesc, "wb");
if (!input || !output) {
return 1;
}
if (targetSize < 0) targetSize = -targetSize;
// STEP1: write input to a file as libgiff didn't work out well with the file descriptor
char fname_in[32] = "/tmp/filestash.XXXXXX";
int _mkstemp_in = mkstemp(fname_in);
if (!_mkstemp_in) {
ERROR("mkstemp_in");
return 1;
}
FILE* f_in = fdopen(_mkstemp_in, "wb");
if (!f_in) {
ERROR("fdopen");
return 1;
}
char content[BUF_SIZE];
int read;
while ((read = fread(content, sizeof(char), BUF_SIZE, input))) {
fwrite(content, read, sizeof(char), f_in);
}
fclose(f_in);
DEBUG("setup");
// STEP2: decode tiff image
TIFF* tif = TIFFOpen(fname_in, "rb");
if (!tif) {
status = 1;
goto CLEANUP_AND_ABORT;
}
DEBUG("init0");
uint32_t w, h;
TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &w);
TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &h);
uint32_t* raster = (uint32_t*)_TIFFmalloc(w * h * sizeof(uint32_t));
if (!raster) {
TIFFClose(tif);
status = 1;
goto CLEANUP_AND_ABORT;
}
DEBUG("init1");
if (!TIFFReadRGBAImageOriented(tif, w, h, raster, ORIENTATION_TOPLEFT, 0)) {
TIFFClose(tif);
status = 1;
goto CLEANUP_AND_ABORT_A;
}
TIFFClose(tif);
DEBUG("read");
// STEP3: resize image
uint8_t* thumbnail_buffer = (uint8_t*)malloc(targetSize * targetSize * 4);
if (!thumbnail_buffer) {
status = 1;
goto CLEANUP_AND_ABORT_A;
}
for (int y = 0; y < targetSize; ++y) {
for (int x = 0; x < targetSize; ++x) {
int srcX = x * w / targetSize;
int srcY = y * h / targetSize;
uint32_t pixel = raster[srcY * w + srcX];
thumbnail_buffer[(y * targetSize + x) * 3 + 0] = TIFFGetR(pixel);
thumbnail_buffer[(y * targetSize + x) * 3 + 1] = TIFFGetG(pixel);
thumbnail_buffer[(y * targetSize + x) * 3 + 2] = TIFFGetB(pixel);
}
}
DEBUG("resized");
// STEP4: encode output image
size_t webp_output_size;
uint8_t* webp_output_data = NULL;
if (!(webp_output_size = WebPEncodeRGB(thumbnail_buffer, targetSize, targetSize, targetSize * 3, 75, &webp_output_data))) {
status = 1;
goto CLEANUP_AND_ABORT_B;
}
DEBUG("encoded");
fwrite(webp_output_data, webp_output_size, 1, output);
fflush(output);
WebPFree(webp_output_data);
DEBUG("done");
CLEANUP_AND_ABORT_B:
free(thumbnail_buffer);
CLEANUP_AND_ABORT_A:
_TIFFfree(raster);
CLEANUP_AND_ABORT:
remove(fname_in);
return status;
}