|
|
@@ -0,0 +1,157 @@ |
|
|
|
#include <stdio.h> |
|
|
|
#include <string.h> |
|
|
|
#include <stdlib.h> |
|
|
|
#include <jpeglib.h> |
|
|
|
#include <omp.h> |
|
|
|
|
|
|
|
unsigned char *process_image( |
|
|
|
unsigned char *input_image, int input_width, int input_height, |
|
|
|
int desired_width, int desired_height) { |
|
|
|
unsigned char *output = calloc(3, desired_width * desired_height); |
|
|
|
|
|
|
|
double scale_w = (double)desired_width / (double)input_width; |
|
|
|
double scale_h = (double)desired_height / (double)input_height; |
|
|
|
double scale; |
|
|
|
printf("scales are %fx%f\n", scale_w, scale_h); |
|
|
|
int rect_x, rect_y, rect_w, rect_h; |
|
|
|
if (scale_w < scale_h) { |
|
|
|
printf("too wide?\n"); |
|
|
|
scale = scale_w; |
|
|
|
} else { |
|
|
|
printf("too tall?\n"); |
|
|
|
scale = scale_h; |
|
|
|
} |
|
|
|
|
|
|
|
rect_w = input_width * scale; |
|
|
|
rect_h = input_height * scale; |
|
|
|
rect_x = (desired_width - rect_w) / 2.0; |
|
|
|
rect_y = (desired_height - rect_h) / 2.0; |
|
|
|
|
|
|
|
printf("rect is %ix%i:%i,%i\n", rect_w, rect_h, rect_x, rect_y); |
|
|
|
|
|
|
|
// Write main image |
|
|
|
#pragma omp parallel for |
|
|
|
for (int y = 0; y < rect_h; ++y) { |
|
|
|
for (int x = 0; x < rect_w; ++x) { |
|
|
|
int input_y = y / scale; |
|
|
|
int input_x = x / scale; |
|
|
|
int input_idx = input_y * input_width * 3 + input_x * 3; |
|
|
|
int output_idx = (y + rect_y) * desired_width * 3 + (x + rect_x) * 3; |
|
|
|
output[output_idx + 0] = input_image[input_idx + 0]; |
|
|
|
output[output_idx + 1] = input_image[input_idx + 1]; |
|
|
|
output[output_idx + 2] = input_image[input_idx + 2]; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return output; |
|
|
|
} |
|
|
|
|
|
|
|
unsigned char *read_jpg(FILE *in, int *width, int *height) { |
|
|
|
struct jpeg_decompress_struct cinfo = { 0 }; |
|
|
|
struct jpeg_error_mgr jerr = { 0 }; |
|
|
|
cinfo.err = jpeg_std_error(&jerr); |
|
|
|
|
|
|
|
jpeg_create_decompress(&cinfo); |
|
|
|
jpeg_stdio_src(&cinfo, in); |
|
|
|
jpeg_read_header(&cinfo, TRUE); |
|
|
|
jpeg_start_decompress(&cinfo); |
|
|
|
|
|
|
|
*width = cinfo.output_width; |
|
|
|
*height = cinfo.output_height; |
|
|
|
int bytes_per_line = cinfo.output_width * 3; |
|
|
|
unsigned char *image = malloc(bytes_per_line * cinfo.output_height); |
|
|
|
|
|
|
|
/* Make a one-row-high sample array that will go away when done with image */ |
|
|
|
JSAMPARRAY buffer = (*cinfo.mem->alloc_sarray) |
|
|
|
((j_common_ptr)&cinfo, JPOOL_IMAGE, bytes_per_line, 1); |
|
|
|
|
|
|
|
while (cinfo.output_scanline < cinfo.output_height) { |
|
|
|
jpeg_read_scanlines(&cinfo, buffer, 1); |
|
|
|
/* Assume put_scanline_someplace wants a pointer and sample count. */ |
|
|
|
memcpy(&image[bytes_per_line * (cinfo.output_scanline - 1)], buffer[0], bytes_per_line); |
|
|
|
} |
|
|
|
|
|
|
|
jpeg_finish_decompress(&cinfo); |
|
|
|
jpeg_destroy_decompress(&cinfo); |
|
|
|
|
|
|
|
return image; |
|
|
|
} |
|
|
|
|
|
|
|
void write_jpg(FILE *out, unsigned char *image, int width, int height) { |
|
|
|
struct jpeg_compress_struct cinfo = { 0 }; |
|
|
|
struct jpeg_error_mgr jerr = { 0 }; |
|
|
|
cinfo.err = jpeg_std_error(&jerr); |
|
|
|
|
|
|
|
jpeg_create_compress(&cinfo); |
|
|
|
jpeg_stdio_dest(&cinfo, out); |
|
|
|
|
|
|
|
printf("writing %ix%i\n", width, height); |
|
|
|
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, 90, FALSE); |
|
|
|
jpeg_start_compress(&cinfo, TRUE); |
|
|
|
|
|
|
|
int bytes_per_line = width * 3; |
|
|
|
JSAMPROW row_pointer[1]; |
|
|
|
|
|
|
|
while (cinfo.next_scanline < cinfo.image_height) { |
|
|
|
row_pointer[0] = &image[cinfo.next_scanline * bytes_per_line]; |
|
|
|
jpeg_write_scanlines(&cinfo, row_pointer, 1); |
|
|
|
} |
|
|
|
|
|
|
|
jpeg_finish_compress(&cinfo); |
|
|
|
jpeg_destroy_compress(&cinfo); |
|
|
|
} |
|
|
|
|
|
|
|
int main(int argc, char **argv) { |
|
|
|
if (argc != 4) { |
|
|
|
printf("Usage: %s <resolution> <input> <output>\n", argv[0]); |
|
|
|
return EXIT_FAILURE; |
|
|
|
} |
|
|
|
|
|
|
|
int desired_width, desired_height; |
|
|
|
if (sscanf(argv[1], "%ix%i", &desired_width, &desired_height) != 2) { |
|
|
|
fprintf(stderr, "Error parsing resolution '%s'\n", argv[1]); |
|
|
|
return EXIT_FAILURE; |
|
|
|
} |
|
|
|
|
|
|
|
FILE *in; |
|
|
|
if (strcmp(argv[2], "-") == 0) { |
|
|
|
in = stdin; |
|
|
|
} else { |
|
|
|
in = fopen(argv[2], "r"); |
|
|
|
if (in == NULL) { |
|
|
|
perror(argv[2]); |
|
|
|
return EXIT_FAILURE; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
int input_width, input_height; |
|
|
|
unsigned char *input_image = read_jpg(in, &input_width, &input_height); |
|
|
|
fclose(in); |
|
|
|
|
|
|
|
unsigned char *output_image = process_image( |
|
|
|
input_image, input_width, input_height, desired_width, desired_height); |
|
|
|
free(input_image); |
|
|
|
|
|
|
|
FILE *out; |
|
|
|
if (strcmp(argv[3], "-") == 0) { |
|
|
|
out = stdout; |
|
|
|
} else { |
|
|
|
out = fopen(argv[3], "w"); |
|
|
|
if (out == NULL) { |
|
|
|
perror(argv[3]); |
|
|
|
free(output_image); |
|
|
|
return EXIT_FAILURE; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
write_jpg(out, output_image, desired_width, desired_height); |
|
|
|
free(output_image); |
|
|
|
|
|
|
|
return EXIT_SUCCESS; |
|
|
|
} |