jpegsrc.c 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. /*
  2. * jpegsrc.c
  3. *
  4. * Copyright (C) 2022-2025 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. static 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. static void custom_init_mem_source (j_decompress_ptr dinfo)
  58. {
  59. /* nothing to do */
  60. }
  61. static boolean custom_fill_input_buffer (j_decompress_ptr dinfo)
  62. {
  63. jpeg_custom_source_mgr_ptr src = (jpeg_custom_source_mgr_ptr) dinfo->src;
  64. size_t bytes_read;
  65. unsigned char *newbuf;
  66. bytes_read = fread(src->stdio_buffer, 1, STDIO_BUFFER_SIZE, src->infile);
  67. if (bytes_read <= 0) {
  68. if (src->start_of_file)
  69. ERREXIT(dinfo, JERR_INPUT_EMPTY);
  70. WARNMS(dinfo, JWRN_JPEG_EOF);
  71. /* Insert fake EOI marker if read failed */
  72. src->stdio_buffer[0] = (JOCTET) 0xff;
  73. src->stdio_buffer[1] = (JOCTET) JPEG_EOI;
  74. bytes_read = 2;
  75. } else if (src->buf_ptr && src->buf) {
  76. if (bytes_read > (src->bufsize - src->bufused)) {
  77. /* Need to allocate more memory for the buffer. */
  78. src->bufsize += src->incsize;
  79. newbuf = realloc(src->buf, src->bufsize);
  80. if (!newbuf) ERREXIT1(dinfo, JERR_OUT_OF_MEMORY, 42);
  81. src->buf = newbuf;
  82. *src->buf_ptr = newbuf;
  83. src->incsize *= 2;
  84. }
  85. memcpy(&src->buf[src->bufused], src->stdio_buffer, bytes_read);
  86. src->bufused += bytes_read;
  87. if (src->bufused_ptr)
  88. *src->bufused_ptr = src->bufused;
  89. }
  90. src->pub.next_input_byte = src->stdio_buffer;
  91. src->pub.bytes_in_buffer = bytes_read;
  92. src->start_of_file = FALSE;
  93. return TRUE;
  94. }
  95. static boolean custom_fill_mem_input_buffer (j_decompress_ptr dinfo)
  96. {
  97. jpeg_custom_source_mgr_ptr src = (jpeg_custom_source_mgr_ptr) dinfo->src;
  98. WARNMS(dinfo, JWRN_JPEG_EOF);
  99. /* Insert fake EOI marker as there is no more data... */
  100. src->stdio_buffer[0] = (JOCTET) 0xff;
  101. src->stdio_buffer[1] = (JOCTET) JPEG_EOI;
  102. src->pub.next_input_byte = src->stdio_buffer;
  103. src->pub.bytes_in_buffer = 2;
  104. return TRUE;
  105. }
  106. static void custom_skip_input_data (j_decompress_ptr dinfo, long num_bytes)
  107. {
  108. jpeg_custom_source_mgr_ptr src = (jpeg_custom_source_mgr_ptr) dinfo->src;
  109. if (num_bytes <= 0)
  110. return;
  111. /* skip "num_bytes" bytes of data from input... */
  112. while (num_bytes > (long) src->pub.bytes_in_buffer) {
  113. num_bytes -= src->pub.bytes_in_buffer;
  114. (void)(src->pub.fill_input_buffer)(dinfo);
  115. }
  116. src->pub.next_input_byte += (size_t) num_bytes;
  117. src->pub.bytes_in_buffer -= (size_t) num_bytes;
  118. }
  119. static void custom_term_source (j_decompress_ptr dinfo)
  120. {
  121. jpeg_custom_source_mgr_ptr src = (jpeg_custom_source_mgr_ptr) dinfo->src;
  122. if (src->bufused_ptr)
  123. *src->bufused_ptr = src->bufused;
  124. }
  125. void jpeg_custom_src(j_decompress_ptr dinfo, FILE *infile,
  126. unsigned char **bufptr, size_t *bufsizeptr, size_t *bufusedptr, size_t incsize)
  127. {
  128. jpeg_custom_source_mgr_ptr src;
  129. if (!dinfo->src) {
  130. /* Allocate source manager object if needed */
  131. dinfo->src = (struct jpeg_source_mgr *)
  132. (*dinfo->mem->alloc_small) ((j_common_ptr) dinfo, JPOOL_PERMANENT,
  133. sizeof(jpeg_custom_source_mgr));
  134. src = (jpeg_custom_source_mgr_ptr) dinfo->src;
  135. src->stdio_buffer = (JOCTET *)
  136. (*dinfo->mem->alloc_small) ((j_common_ptr) dinfo, JPOOL_PERMANENT,
  137. STDIO_BUFFER_SIZE * sizeof(JOCTET));
  138. } else {
  139. src = (jpeg_custom_source_mgr_ptr) dinfo->src;
  140. }
  141. src->pub.init_source = custom_init_source;
  142. src->pub.fill_input_buffer = custom_fill_input_buffer;
  143. src->pub.resync_to_restart = jpeg_resync_to_restart;
  144. src->pub.skip_input_data = custom_skip_input_data;
  145. src->pub.term_source = custom_term_source;
  146. src->infile = infile;
  147. src->pub.bytes_in_buffer = 0;
  148. src->pub.next_input_byte = NULL;
  149. src->buf_ptr = bufptr;
  150. src->buf = (bufptr ? *bufptr : NULL);
  151. src->bufsize_ptr = bufsizeptr;
  152. src->bufused_ptr = bufusedptr;
  153. src->bufsize = (bufsizeptr ? *bufsizeptr : 0);
  154. src->incsize = incsize;
  155. }
  156. void jpeg_custom_mem_src(j_decompress_ptr dinfo, unsigned char *buf, size_t bufsize)
  157. {
  158. jpeg_custom_source_mgr_ptr src;
  159. if (!dinfo->src) {
  160. /* Allocate source manager object if needed */
  161. dinfo->src = (struct jpeg_source_mgr *)
  162. (*dinfo->mem->alloc_small) ((j_common_ptr) dinfo, JPOOL_PERMANENT,
  163. sizeof(jpeg_custom_source_mgr));
  164. src = (jpeg_custom_source_mgr_ptr) dinfo->src;
  165. src->stdio_buffer = (JOCTET *)
  166. (*dinfo->mem->alloc_small) ((j_common_ptr) dinfo, JPOOL_PERMANENT,
  167. STDIO_BUFFER_SIZE * sizeof(JOCTET));
  168. } else {
  169. src = (jpeg_custom_source_mgr_ptr) dinfo->src;
  170. }
  171. src->pub.init_source = custom_init_mem_source;
  172. src->pub.fill_input_buffer = custom_fill_mem_input_buffer;
  173. src->pub.resync_to_restart = jpeg_resync_to_restart;
  174. src->pub.skip_input_data = custom_skip_input_data;
  175. src->pub.term_source = custom_term_source;
  176. src->infile = NULL;
  177. src->pub.bytes_in_buffer = bufsize;
  178. src->pub.next_input_byte = (JOCTET*) buf;
  179. src->buf_ptr = NULL;
  180. src->buf = NULL;
  181. src->bufsize_ptr = NULL;
  182. src->bufused_ptr = NULL;
  183. src->bufsize = bufsize;
  184. src->incsize = 0;
  185. }
  186. /* eof :-) */