Simple and fast tool to add a fancy blurred letterbox effect to images.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

blurrerbox.c 4.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <stdlib.h>
  4. #include <jpeglib.h>
  5. #include <omp.h>
  6. unsigned char *process_image(
  7. unsigned char *input_image, int input_width, int input_height,
  8. int desired_width, int desired_height) {
  9. unsigned char *output = calloc(3, desired_width * desired_height);
  10. double scale_w = (double)desired_width / (double)input_width;
  11. double scale_h = (double)desired_height / (double)input_height;
  12. double scale;
  13. printf("scales are %fx%f\n", scale_w, scale_h);
  14. int rect_x, rect_y, rect_w, rect_h;
  15. if (scale_w < scale_h) {
  16. printf("too wide?\n");
  17. scale = scale_w;
  18. } else {
  19. printf("too tall?\n");
  20. scale = scale_h;
  21. }
  22. rect_w = input_width * scale;
  23. rect_h = input_height * scale;
  24. rect_x = (desired_width - rect_w) / 2.0;
  25. rect_y = (desired_height - rect_h) / 2.0;
  26. printf("rect is %ix%i:%i,%i\n", rect_w, rect_h, rect_x, rect_y);
  27. // Write main image
  28. #pragma omp parallel for
  29. for (int y = 0; y < rect_h; ++y) {
  30. for (int x = 0; x < rect_w; ++x) {
  31. int input_y = y / scale;
  32. int input_x = x / scale;
  33. int input_idx = input_y * input_width * 3 + input_x * 3;
  34. int output_idx = (y + rect_y) * desired_width * 3 + (x + rect_x) * 3;
  35. output[output_idx + 0] = input_image[input_idx + 0];
  36. output[output_idx + 1] = input_image[input_idx + 1];
  37. output[output_idx + 2] = input_image[input_idx + 2];
  38. }
  39. }
  40. return output;
  41. }
  42. unsigned char *read_jpg(FILE *in, int *width, int *height) {
  43. struct jpeg_decompress_struct cinfo = { 0 };
  44. struct jpeg_error_mgr jerr = { 0 };
  45. cinfo.err = jpeg_std_error(&jerr);
  46. jpeg_create_decompress(&cinfo);
  47. jpeg_stdio_src(&cinfo, in);
  48. jpeg_read_header(&cinfo, TRUE);
  49. jpeg_start_decompress(&cinfo);
  50. *width = cinfo.output_width;
  51. *height = cinfo.output_height;
  52. int bytes_per_line = cinfo.output_width * 3;
  53. unsigned char *image = malloc(bytes_per_line * cinfo.output_height);
  54. /* Make a one-row-high sample array that will go away when done with image */
  55. JSAMPARRAY buffer = (*cinfo.mem->alloc_sarray)
  56. ((j_common_ptr)&cinfo, JPOOL_IMAGE, bytes_per_line, 1);
  57. while (cinfo.output_scanline < cinfo.output_height) {
  58. jpeg_read_scanlines(&cinfo, buffer, 1);
  59. /* Assume put_scanline_someplace wants a pointer and sample count. */
  60. memcpy(&image[bytes_per_line * (cinfo.output_scanline - 1)], buffer[0], bytes_per_line);
  61. }
  62. jpeg_finish_decompress(&cinfo);
  63. jpeg_destroy_decompress(&cinfo);
  64. return image;
  65. }
  66. void write_jpg(FILE *out, unsigned char *image, int width, int height) {
  67. struct jpeg_compress_struct cinfo = { 0 };
  68. struct jpeg_error_mgr jerr = { 0 };
  69. cinfo.err = jpeg_std_error(&jerr);
  70. jpeg_create_compress(&cinfo);
  71. jpeg_stdio_dest(&cinfo, out);
  72. printf("writing %ix%i\n", width, height);
  73. cinfo.image_width = width;
  74. cinfo.image_height = height;
  75. cinfo.input_components = 3;
  76. cinfo.in_color_space = JCS_RGB;
  77. jpeg_set_defaults(&cinfo);
  78. jpeg_set_quality(&cinfo, 90, FALSE);
  79. jpeg_start_compress(&cinfo, TRUE);
  80. int bytes_per_line = width * 3;
  81. JSAMPROW row_pointer[1];
  82. while (cinfo.next_scanline < cinfo.image_height) {
  83. row_pointer[0] = &image[cinfo.next_scanline * bytes_per_line];
  84. jpeg_write_scanlines(&cinfo, row_pointer, 1);
  85. }
  86. jpeg_finish_compress(&cinfo);
  87. jpeg_destroy_compress(&cinfo);
  88. }
  89. int main(int argc, char **argv) {
  90. if (argc != 4) {
  91. printf("Usage: %s <resolution> <input> <output>\n", argv[0]);
  92. return EXIT_FAILURE;
  93. }
  94. int desired_width, desired_height;
  95. if (sscanf(argv[1], "%ix%i", &desired_width, &desired_height) != 2) {
  96. fprintf(stderr, "Error parsing resolution '%s'\n", argv[1]);
  97. return EXIT_FAILURE;
  98. }
  99. FILE *in;
  100. if (strcmp(argv[2], "-") == 0) {
  101. in = stdin;
  102. } else {
  103. in = fopen(argv[2], "r");
  104. if (in == NULL) {
  105. perror(argv[2]);
  106. return EXIT_FAILURE;
  107. }
  108. }
  109. int input_width, input_height;
  110. unsigned char *input_image = read_jpg(in, &input_width, &input_height);
  111. fclose(in);
  112. unsigned char *output_image = process_image(
  113. input_image, input_width, input_height, desired_width, desired_height);
  114. free(input_image);
  115. FILE *out;
  116. if (strcmp(argv[3], "-") == 0) {
  117. out = stdout;
  118. } else {
  119. out = fopen(argv[3], "w");
  120. if (out == NULL) {
  121. perror(argv[3]);
  122. free(output_image);
  123. return EXIT_FAILURE;
  124. }
  125. }
  126. write_jpg(out, output_image, desired_width, desired_height);
  127. free(output_image);
  128. return EXIT_SUCCESS;
  129. }