#include #include #include #include #include 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 \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; }