#include <stdio.h>
#include <stdlib.h>
#include <tiffio.h>
#include <jpeglib.h>

int main(int argc, char *argv[]) {
    int                         ret      = EXIT_FAILURE;
    TIFF                        *tif     = NULL;
    uint32_t                    *raster  = NULL;
    FILE                        *outfile = NULL;
    JSAMPROW                    row      = NULL;
    uint32_t                    width, height;
    struct jpeg_compress_struct cinfo;
    struct jpeg_error_mgr       jerr;

    if (argc != 3) {
        fprintf(stderr, "Usage: %s input.tif output.jpg\n", argv[0]);
        goto cleanup;
    }

    if (!(outfile = fopen(argv[2], "wb"))) {
        fprintf(stderr, "Cannot open output %s\n", argv[2]);
        goto cleanup;
    }

    if (!(tif = TIFFOpen(argv[1], "r"))) {
        fprintf(stderr, "Cannot open TIFF %s\n", argv[1]);
        goto cleanup;
    }

    TIFFGetField(tif, TIFFTAG_IMAGEWIDTH,  &width);
    TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height);
    if (!(raster = (uint32_t *)_TIFFmalloc(width * height * sizeof(uint32_t)))) {
        fprintf(stderr, "Out of memory allocating raster\n");
        goto cleanup;
    }

    if (!TIFFReadRGBAImage(tif, width, height, raster, 0)) {
        fprintf(stderr, "TIFFReadRGBAImage failed\n");
        goto cleanup;
    }

    cinfo.err = jpeg_std_error(&jerr);
    jpeg_create_compress(&cinfo);
    jpeg_stdio_dest(&cinfo, outfile);

    cinfo.image_width      = width;
    cinfo.image_height     = height;
    cinfo.input_components = 3;
    cinfo.in_color_space   = JCS_RGB;
    jpeg_set_defaults(&cinfo);
    jpeg_set_quality(&cinfo, 100, TRUE);
    jpeg_start_compress(&cinfo, TRUE);

    if (!(row = (JSAMPROW)malloc(3 * width))) {
        fprintf(stderr, "Out of memory allocating scanline buffer\n");
        goto cleanup;
    }

    while (cinfo.next_scanline < cinfo.image_height) {
        uint32_t src_row = height - cinfo.next_scanline - 1;
        uint32_t *src    = raster + src_row * width;
        for (uint32_t x = 0; x < width; ++x) {
            uint32_t pix = src[x];
            row[x*3 + 0] = TIFFGetR(pix);
            row[x*3 + 1] = TIFFGetG(pix);
            row[x*3 + 2] = TIFFGetB(pix);
        }
        jpeg_write_scanlines(&cinfo, &row, 1);
    }
    jpeg_finish_compress(&cinfo);
    ret = EXIT_SUCCESS;

cleanup:
    jpeg_destroy_compress(&cinfo);
    if (row)                   free(row);
    if (outfile)               fclose(outfile);
    if (raster)                _TIFFfree(raster);
    if (tif)                   TIFFClose(tif);
    return ret;
}
