Skip to content

Commit

Permalink
refactor: file format handling moved to separate files
Browse files Browse the repository at this point in the history
  • Loading branch information
ntamas committed Sep 13, 2023
1 parent 363a1a1 commit a15bc5a
Show file tree
Hide file tree
Showing 9 changed files with 336 additions and 253 deletions.
8 changes: 7 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,13 @@ configure_file(
)

# Declare final target
set(STITCH_SOURCES src/stitch.c)
set(
STITCH_SOURCES
src/stitch.c
src/formats/geotiff.c
src/formats/jpeg.c
src/formats/png.c
)
if(NOT HAVE_GETOPT_H)
list(APPEND STITCH_SOURCES src/getopt.c)
endif()
Expand Down
85 changes: 85 additions & 0 deletions src/formats/geotiff.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
#include "config.h"
#include "geotiff.h"

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

#if GEOTIFF_FOUND
# include <geotiffio.h>
# include <xtiffio.h>

int write_geotiff(const char* outfile, int width, int height, unsigned char** rows, int px, int py, int minx, int maxy) {
int i;

//TODO : Handle writing to stdout if required

if (outfile != NULL) {
fprintf(stderr, "Output TIFF: %s\n", outfile);

Check warning on line 17 in src/formats/geotiff.c

View workflow job for this annotation

GitHub Actions / windows-latest-hosted-ninja-vcpkg_submod-autocache

'fprintf': function not inlined
TIFF *tif = (TIFF *) 0; /* TIFF-level descriptor */
GTIF *gtif = (GTIF *) 0; /* GeoKey-level descriptor */

tif = XTIFFOpen(outfile, "w");
if (!tif) {
fprintf(stderr, "TIF failure (open)\n");

Check warning on line 23 in src/formats/geotiff.c

View workflow job for this annotation

GitHub Actions / windows-latest-hosted-ninja-vcpkg_submod-autocache

'fprintf': function not inlined
exit(EXIT_FAILURE);
}

gtif = GTIFNew(tif);
if (!gtif) {
printf("GTIFF failure (geotiff struct)\n");

Check warning on line 29 in src/formats/geotiff.c

View workflow job for this annotation

GitHub Actions / windows-latest-hosted-ninja-vcpkg_submod-autocache

'printf': function not inlined
exit(EXIT_FAILURE);
}

//georeference the image using the upper left projected bound
//as a tie point, and the pixel scale
double pixscale[3] = {px, py, 0};
double tiepoints[6] = {0, 0, 0, minx, maxy, 0.0};
TIFFSetField(tif, TIFFTAG_GEOPIXELSCALE, 3, pixscale);
TIFFSetField(tif, TIFFTAG_GEOTIEPOINTS, 6, tiepoints);

TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, width);
TIFFSetField(tif, TIFFTAG_IMAGELENGTH, height);
TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_LZW);
TIFFSetField(tif, TIFFTAG_PREDICTOR, 2); //(horizontal differencing)
TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 8);
TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, 20L);
TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 4); //RGB+ALPHA
TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);

GTIFKeySet(gtif, GTModelTypeGeoKey, TYPE_SHORT, 1, ModelTypeProjected);
GTIFKeySet(gtif, GTRasterTypeGeoKey, TYPE_SHORT, 1, RasterPixelIsArea);
GTIFKeySet(gtif, GTCitationGeoKey, TYPE_ASCII, 0, "WGS 84 / Pseudo-Mercator");
GTIFKeySet(gtif, GeogCitationGeoKey, TYPE_ASCII, 0, "WGS 84");
GTIFKeySet(gtif, GeogAngularUnitsGeoKey, TYPE_SHORT, 1, Angular_Degree);
GTIFKeySet(gtif, GeogLinearUnitsGeoKey, TYPE_SHORT, 1, Linear_Meter);
GTIFKeySet(gtif, ProjectedCSTypeGeoKey, TYPE_SHORT, 1, 3857);

//write raster image
for (i = 0; i < height; i++) {
if (!TIFFWriteScanline(tif, rows[i], i, 0)) {
TIFFError("WriteImage", "failure in WriteScanline\n");
return EXIT_FAILURE;
}
}

GTIFWriteKeys(gtif);
GTIFFree(gtif);
XTIFFClose(tif);
} else {
fprintf(stderr, "Can't write TIFF to stdout, sorry\n");
return EXIT_FAILURE;
}

return EXIT_SUCCESS;
}

#else /* GEOTIFF_FOUND */

int write_geotiff(const char* outfile, int width, int height, void* rows) {
fprintf(stderr, "stitch was compiled without GeoTIFF support, sorry\n");
return EXIT_FAILURE;
}

#endif /* GEOTIFF_FOUND */

8 changes: 8 additions & 0 deletions src/formats/geotiff.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#pragma once

#include "image.h"

int write_geotiff(
const char* outfile, int width, int height, unsigned char** rows,
int px, int py, int minx, int maxy
);
8 changes: 8 additions & 0 deletions src/formats/image.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#pragma once

struct image {
unsigned char *buf;
int depth;
int width;
int height;
};

Check warning on line 8 in src/formats/image.h

View workflow job for this annotation

GitHub Actions / windows-latest-hosted-ninja-vcpkg_submod-autocache

'image': '4' bytes padding added after data member 'height'

Check warning on line 8 in src/formats/image.h

View workflow job for this annotation

GitHub Actions / windows-latest-hosted-ninja-vcpkg_submod-autocache

'image': '4' bytes padding added after data member 'height'
60 changes: 60 additions & 0 deletions src/formats/jpeg.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#include "config.h"
#include "jpeg.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#if JPEG_FOUND
# include <jpeglib.h>

struct image *read_jpeg(char *s, int len) {
struct jpeg_decompress_struct cinfo;
struct jpeg_error_mgr jerr;

cinfo.err = jpeg_std_error(&jerr);
jpeg_create_decompress(&cinfo);
jpeg_mem_src(&cinfo, (unsigned char *) s, len);
jpeg_read_header(&cinfo, TRUE);
jpeg_start_decompress(&cinfo);

int row_stride = cinfo.output_width * cinfo.output_components;
JSAMPARRAY buffer = (*cinfo.mem->alloc_sarray)((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1);

struct image *i = malloc(sizeof(struct image));
i->buf = malloc(cinfo.output_width * cinfo.output_height * cinfo.output_components);
i->width = cinfo.output_width;
i->height = cinfo.output_height;
i->depth = cinfo.output_components;

unsigned char *here = i->buf;
while (cinfo.output_scanline < cinfo.output_height) {
jpeg_read_scanlines(&cinfo, buffer, 1);
memcpy(here, buffer[0], row_stride);
here += row_stride;
}

jpeg_finish_decompress(&cinfo);
jpeg_destroy_decompress(&cinfo);

return i;
}

int write_jpeg(const char* outfile, int width, int height, void* rows) {

Check warning on line 43 in src/formats/jpeg.c

View workflow job for this annotation

GitHub Actions / windows-latest-hosted-ninja-vcpkg_submod-autocache

'rows': unreferenced formal parameter

Check warning on line 43 in src/formats/jpeg.c

View workflow job for this annotation

GitHub Actions / windows-latest-hosted-ninja-vcpkg_submod-autocache

'height': unreferenced formal parameter

Check warning on line 43 in src/formats/jpeg.c

View workflow job for this annotation

GitHub Actions / windows-latest-hosted-ninja-vcpkg_submod-autocache

'width': unreferenced formal parameter

Check warning on line 43 in src/formats/jpeg.c

View workflow job for this annotation

GitHub Actions / windows-latest-hosted-ninja-vcpkg_submod-autocache

'outfile': unreferenced formal parameter
fprintf(stderr, "Not implemented yet, sorry\n");

Check warning on line 44 in src/formats/jpeg.c

View workflow job for this annotation

GitHub Actions / windows-latest-hosted-ninja-vcpkg_submod-autocache

'fprintf': function not inlined
return EXIT_FAILURE;
}

#else /* JPEG_FOUND */

struct image *read_jpeg(char *s, int len) {
fprintf(stderr, "stitch was compiled without JPEG support, sorry\n");
return 0;
}

int write_jpeg(const char* outfile, int width, int height, void* rows) {
fprintf(stderr, "stitch was compiled without JPEG support, sorry\n");
return EXIT_FAILURE;
}

#endif /* JPEG_FOUND */
6 changes: 6 additions & 0 deletions src/formats/jpeg.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#pragma once

#include "image.h"

struct image *read_jpeg(char *s, int len);
int write_jpeg(const char* outfile, int width, int height, void* rows);
136 changes: 136 additions & 0 deletions src/formats/png.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
#include "config.h"
#include "png.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#if PNG_FOUND
# include <png.h>

static void fail(png_structp png_ptr, png_const_charp error_msg) {
fprintf(stderr, "PNG error %s\n", error_msg);
exit(EXIT_FAILURE);
}

struct read_state {
char *base;
int off;
int len;
};

static void user_read_data(png_structp png_ptr, png_bytep data, png_size_t length) {
struct read_state *state = png_get_io_ptr(png_ptr);

if (state->off + length > state->len) {
length = state->len - state->off;
}

memcpy(data, state->base + state->off, length);
state->off += length;
}

struct image *read_png(char *s, int len) {
png_structp png_ptr;
png_infop info_ptr;

struct read_state state;
state.base = s;
state.off = 0;
state.len = len;

png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, fail, fail, fail);
if (png_ptr == NULL) {
fprintf(stderr, "PNG init failed\n");
exit(EXIT_FAILURE);
}

info_ptr = png_create_info_struct(png_ptr);
if (info_ptr == NULL) {
fprintf(stderr, "PNG init failed\n");
exit(EXIT_FAILURE);
}

png_set_read_fn(png_ptr, &state, user_read_data);
png_set_sig_bytes(png_ptr, 0);

png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_PACKING | PNG_TRANSFORM_EXPAND, NULL);

png_uint_32 width, height;
int bit_depth;
int color_type, interlace_type;

png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL);

struct image *i = malloc(sizeof(struct image));
i->width = width;
i->height = height;
i->depth = png_get_channels(png_ptr, info_ptr);
i->buf = malloc(i->width * i->height * i->depth);

unsigned int row_bytes = png_get_rowbytes(png_ptr, info_ptr);
png_bytepp row_pointers = png_get_rows(png_ptr, info_ptr);

int n;
for (n = 0; n < i->height; n++) {
memcpy(i->buf + row_bytes * n, row_pointers[n], row_bytes);
}

png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
return i;
}

int write_png(const char* outfile, int width, int height, void* rows) {
FILE *outfp = stdout;
if (outfile != NULL) {
fprintf(stderr, "Output PNG: %s\n", outfile);
outfp = fopen(outfile, "wb");
if (outfp == NULL) {
perror(outfile);
exit(EXIT_FAILURE);
}
} else {
fprintf(stderr, "Output PNG: stdout\n");
}
png_structp png_ptr;
png_infop info_ptr;

png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, fail, fail, fail);
if (png_ptr == NULL) {
fprintf(stderr, "PNG failure (write struct)\n");
return EXIT_FAILURE;
}
info_ptr = png_create_info_struct(png_ptr);
if (info_ptr == NULL) {
png_destroy_write_struct(&png_ptr, NULL);
fprintf(stderr, "PNG failure (info struct)\n");
return EXIT_FAILURE;
}

png_set_IHDR(png_ptr, info_ptr, width, height, 8, PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
png_set_rows(png_ptr, info_ptr, rows);
png_init_io(png_ptr, outfp);
png_write_png(png_ptr, info_ptr, 0, NULL);
png_destroy_write_struct(&png_ptr, &info_ptr);

if (outfile != NULL) {
fclose(outfp);
}

return EXIT_SUCCESS;
}

#else /* PNG_FOUND */

struct image *read_png(char *s, int len) {
fprintf(stderr, "stitch was compiled without PNG support, sorry\n");
return 0;
}


int write_png(const char* outfile, int width, int height, void* rows) {
fprintf(stderr, "stitch was compiled without PNG support, sorry\n");
return EXIT_FAILURE;
}

#endif /* PNG_FOUND */
6 changes: 6 additions & 0 deletions src/formats/png.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#pragma once

#include "image.h"

struct image *read_png(char *s, int len);
int write_png(const char* outfile, int width, int height, void* rows);
Loading

0 comments on commit a15bc5a

Please sign in to comment.