jpegsrc.c 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. /*
  2. * jpegsrc.c
  3. *
  4. * Copyright (C) 2022 Timo Kokkonen
  5. * All Rights Reserved.
  6. *
  7. * Custom libjpeg "Source Manager" for reading from a file handle
  8. * and optionally saving the input also into a memory buffer.
  9. *
  10. * SPDX-License-Identifier: GPL-3.0-or-later
  11. *
  12. * This file is part of JPEGoptim.
  13. *
  14. * JPEGoptim is free software: you can redistribute it and/or modify
  15. * it under the terms of the GNU General Public License as published by
  16. * the Free Software Foundation, either version 3 of the License, or
  17. * (at your option) any later version.
  18. *
  19. * JPEGoptim is distributed in the hope that it will be useful,
  20. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  21. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  22. * GNU General Public License for more details.
  23. *
  24. * You should have received a copy of the GNU General Public License
  25. * along with JPEGoptim. If not, see <https://www.gnu.org/licenses/>.
  26. */
  27. #include <stdio.h>
  28. #include <stdlib.h>
  29. #include <string.h>
  30. #include <jpeglib.h>
  31. #include <jerror.h>
  32. #include "jpegoptim.h"
  33. #define STDIO_BUFFER_SIZE 4096
  34. /* Custom jpeg source manager object */
  35. typedef struct {
  36. struct jpeg_source_mgr pub; /* public fields */
  37. unsigned char **buf_ptr;
  38. size_t *bufsize_ptr;
  39. size_t *bufused_ptr;
  40. size_t incsize;
  41. unsigned char *buf;
  42. size_t bufsize;
  43. size_t bufused;
  44. FILE *infile;
  45. JOCTET *stdio_buffer;
  46. boolean start_of_file;
  47. } jpeg_custom_source_mgr;
  48. typedef jpeg_custom_source_mgr* jpeg_custom_source_mgr_ptr;
  49. void custom_init_source (j_decompress_ptr dinfo)
  50. {
  51. jpeg_custom_source_mgr_ptr src = (jpeg_custom_source_mgr_ptr) dinfo->src;
  52. src->bufused = 0;
  53. if (src->bufused_ptr)
  54. *src->bufused_ptr = 0;
  55. src->start_of_file = TRUE;
  56. }
  57. boolean custom_fill_input_buffer (j_decompress_ptr dinfo)
  58. {
  59. jpeg_custom_source_mgr_ptr src = (jpeg_custom_source_mgr_ptr) dinfo->src;
  60. size_t bytes_read;
  61. unsigned char *newbuf;
  62. bytes_read = fread(src->stdio_buffer, 1, STDIO_BUFFER_SIZE, src->infile);
  63. if (bytes_read <= 0) {
  64. if (src->start_of_file)
  65. ERREXIT(dinfo, JERR_INPUT_EMPTY);
  66. WARNMS(dinfo, JWRN_JPEG_EOF);
  67. /* Insert fake EOI marker if read failed */
  68. src->stdio_buffer[0] = (JOCTET) 0xff;
  69. src->stdio_buffer[1] = (JOCTET) JPEG_EOI;
  70. bytes_read = 2;
  71. } else if (src->buf_ptr && src->buf) {
  72. if (bytes_read > (src->bufsize - src->bufused)) {
  73. /* Need to allocate more memory for the buffer. */
  74. src->bufsize += src->incsize;
  75. newbuf = realloc(src->buf, src->bufsize);
  76. if (!newbuf) ERREXIT1(dinfo, JERR_OUT_OF_MEMORY, 42);
  77. src->buf = newbuf;
  78. *src->buf_ptr = newbuf;
  79. src->incsize *= 2;
  80. }
  81. memcpy(&src->buf[src->bufused], src->stdio_buffer, bytes_read);
  82. src->bufused += bytes_read;
  83. if (src->bufused_ptr)
  84. *src->bufused_ptr = src->bufused;
  85. }
  86. src->pub.next_input_byte = src->stdio_buffer;
  87. src->pub.bytes_in_buffer = bytes_read;
  88. src->start_of_file = FALSE;
  89. return TRUE;
  90. }
  91. void custom_skip_input_data (j_decompress_ptr dinfo, long num_bytes)
  92. {
  93. jpeg_custom_source_mgr_ptr src = (jpeg_custom_source_mgr_ptr) dinfo->src;
  94. if (num_bytes <= 0)
  95. return;
  96. /* skip "num_bytes" bytes of data from input... */
  97. while (num_bytes > (long) src->pub.bytes_in_buffer) {
  98. num_bytes -= src->pub.bytes_in_buffer;
  99. (void) custom_fill_input_buffer(dinfo);
  100. }
  101. src->pub.next_input_byte += (size_t) num_bytes;
  102. src->pub.bytes_in_buffer -= (size_t) num_bytes;
  103. }
  104. void custom_term_source (j_decompress_ptr dinfo)
  105. {
  106. jpeg_custom_source_mgr_ptr src = (jpeg_custom_source_mgr_ptr) dinfo->src;
  107. if (src->bufused_ptr)
  108. *src->bufused_ptr = src->bufused;
  109. }
  110. void jpeg_custom_src(j_decompress_ptr dinfo, FILE *infile,
  111. unsigned char **bufptr, size_t *bufsizeptr, size_t *bufusedptr, size_t incsize)
  112. {
  113. jpeg_custom_source_mgr_ptr src;
  114. if (!dinfo->src) {
  115. /* Allocate source manager object if needed */
  116. dinfo->src = (struct jpeg_source_mgr *)
  117. (*dinfo->mem->alloc_small) ((j_common_ptr) dinfo, JPOOL_PERMANENT,
  118. sizeof(jpeg_custom_source_mgr));
  119. src = (jpeg_custom_source_mgr_ptr) dinfo->src;
  120. src->stdio_buffer = (JOCTET *)
  121. (*dinfo->mem->alloc_small) ((j_common_ptr) dinfo, JPOOL_PERMANENT,
  122. STDIO_BUFFER_SIZE * sizeof(JOCTET));
  123. } else {
  124. src = (jpeg_custom_source_mgr_ptr) dinfo->src;
  125. }
  126. src->pub.init_source = custom_init_source;
  127. src->pub.fill_input_buffer = custom_fill_input_buffer;
  128. src->pub.resync_to_restart = jpeg_resync_to_restart;
  129. src->pub.skip_input_data = custom_skip_input_data;
  130. src->pub.term_source = custom_term_source;
  131. src->infile = infile;
  132. src->pub.bytes_in_buffer = 0;
  133. src->pub.next_input_byte = NULL;
  134. src->buf_ptr = bufptr;
  135. src->buf = (bufptr ? *bufptr : NULL);
  136. src->bufsize_ptr = bufsizeptr;
  137. src->bufused_ptr = bufusedptr;
  138. src->bufsize = (bufsizeptr ? *bufsizeptr : 0);
  139. src->incsize = incsize;
  140. }
  141. /* eof :-) */