1 /* 2 * jdatadst.c 3 * 4 * This file was part of the Independent JPEG Group's software: 5 * Copyright (C) 1994-1996, Thomas G. Lane. 6 * Modified 2009-2012 by Guido Vollbeding. 7 * libjpeg-turbo Modifications: 8 * Copyright (C) 2013, 2016, D. R. Commander. 9 * For conditions of distribution and use, see the accompanying README.ijg 10 * file. 11 * 12 * This file contains compression data destination routines for the case of 13 * emitting JPEG data to memory or to a file (or any stdio stream). 14 * While these routines are sufficient for most applications, 15 * some will want to use a different destination manager. 16 * IMPORTANT: we assume that fwrite() will correctly transcribe an array of 17 * JOCTETs into 8-bit-wide elements on external storage. If char is wider 18 * than 8 bits on your machine, you may need to do some tweaking. 19 */ 20 21 /* this is not a core library module, so it doesn't define JPEG_INTERNALS */ 22 #include "jinclude.h" 23 #include "jpeglib.h" 24 #include "jerror.h" 25 26 #ifndef HAVE_STDLIB_H /* <stdlib.h> should declare malloc(),free() */ 27 extern void *malloc (size_t size); 28 extern void free (void *ptr); 29 #endif 30 31 32 /* Expanded data destination object for stdio output */ 33 34 typedef struct { 35 struct jpeg_destination_mgr pub; /* public fields */ 36 37 FILE *outfile; /* target stream */ 38 JOCTET *buffer; /* start of buffer */ 39 } my_destination_mgr; 40 41 typedef my_destination_mgr *my_dest_ptr; 42 43 #define OUTPUT_BUF_SIZE 4096 /* choose an efficiently fwrite'able size */ 44 45 46 #if JPEG_LIB_VERSION >= 80 || defined(MEM_SRCDST_SUPPORTED) 47 /* Expanded data destination object for memory output */ 48 49 typedef struct { 50 struct jpeg_destination_mgr pub; /* public fields */ 51 52 unsigned char **outbuffer; /* target buffer */ 53 unsigned long *outsize; 54 unsigned char *newbuffer; /* newly allocated buffer */ 55 JOCTET *buffer; /* start of buffer */ 56 size_t bufsize; 57 } my_mem_destination_mgr; 58 59 typedef my_mem_destination_mgr *my_mem_dest_ptr; 60 #endif 61 62 63 /* 64 * Initialize destination --- called by jpeg_start_compress 65 * before any data is actually written. 66 */ 67 68 METHODDEF(void) 69 init_destination (j_compress_ptr cinfo) 70 { 71 my_dest_ptr dest = (my_dest_ptr) cinfo->dest; 72 73 /* Allocate the output buffer --- it will be released when done with image */ 74 dest->buffer = (JOCTET *) 75 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, 76 OUTPUT_BUF_SIZE * sizeof(JOCTET)); 77 78 dest->pub.next_output_byte = dest->buffer; 79 dest->pub.free_in_buffer = OUTPUT_BUF_SIZE; 80 } 81 82 #if JPEG_LIB_VERSION >= 80 || defined(MEM_SRCDST_SUPPORTED) 83 METHODDEF(void) 84 init_mem_destination (j_compress_ptr cinfo) 85 { 86 /* no work necessary here */ 87 } 88 #endif 89 90 91 /* 92 * Empty the output buffer --- called whenever buffer fills up. 93 * 94 * In typical applications, this should write the entire output buffer 95 * (ignoring the current state of next_output_byte & free_in_buffer), 96 * reset the pointer & count to the start of the buffer, and return TRUE 97 * indicating that the buffer has been dumped. 98 * 99 * In applications that need to be able to suspend compression due to output 100 * overrun, a FALSE return indicates that the buffer cannot be emptied now. 101 * In this situation, the compressor will return to its caller (possibly with 102 * an indication that it has not accepted all the supplied scanlines). The 103 * application should resume compression after it has made more room in the 104 * output buffer. Note that there are substantial restrictions on the use of 105 * suspension --- see the documentation. 106 * 107 * When suspending, the compressor will back up to a convenient restart point 108 * (typically the start of the current MCU). next_output_byte & free_in_buffer 109 * indicate where the restart point will be if the current call returns FALSE. 110 * Data beyond this point will be regenerated after resumption, so do not 111 * write it out when emptying the buffer externally. 112 */ 113 114 METHODDEF(boolean) 115 empty_output_buffer (j_compress_ptr cinfo) 116 { 117 my_dest_ptr dest = (my_dest_ptr) cinfo->dest; 118 119 if (JFWRITE(dest->outfile, dest->buffer, OUTPUT_BUF_SIZE) != 120 (size_t) OUTPUT_BUF_SIZE) 121 ERREXIT(cinfo, JERR_FILE_WRITE); 122 123 dest->pub.next_output_byte = dest->buffer; 124 dest->pub.free_in_buffer = OUTPUT_BUF_SIZE; 125 126 return TRUE; 127 } 128 129 #if JPEG_LIB_VERSION >= 80 || defined(MEM_SRCDST_SUPPORTED) 130 METHODDEF(boolean) 131 empty_mem_output_buffer (j_compress_ptr cinfo) 132 { 133 size_t nextsize; 134 JOCTET *nextbuffer; 135 my_mem_dest_ptr dest = (my_mem_dest_ptr) cinfo->dest; 136 137 /* Try to allocate new buffer with double size */ 138 nextsize = dest->bufsize * 2; 139 nextbuffer = (JOCTET *) malloc(nextsize); 140 141 if (nextbuffer == NULL) 142 ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, 10); 143 144 MEMCOPY(nextbuffer, dest->buffer, dest->bufsize); 145 146 if (dest->newbuffer != NULL) 147 free(dest->newbuffer); 148 149 dest->newbuffer = nextbuffer; 150 151 dest->pub.next_output_byte = nextbuffer + dest->bufsize; 152 dest->pub.free_in_buffer = dest->bufsize; 153 154 dest->buffer = nextbuffer; 155 dest->bufsize = nextsize; 156 157 return TRUE; 158 } 159 #endif 160 161 162 /* 163 * Terminate destination --- called by jpeg_finish_compress 164 * after all data has been written. Usually needs to flush buffer. 165 * 166 * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding 167 * application must deal with any cleanup that should happen even 168 * for error exit. 169 */ 170 171 METHODDEF(void) 172 term_destination (j_compress_ptr cinfo) 173 { 174 my_dest_ptr dest = (my_dest_ptr) cinfo->dest; 175 size_t datacount = OUTPUT_BUF_SIZE - dest->pub.free_in_buffer; 176 177 /* Write any data remaining in the buffer */ 178 if (datacount > 0) { 179 if (JFWRITE(dest->outfile, dest->buffer, datacount) != datacount) 180 ERREXIT(cinfo, JERR_FILE_WRITE); 181 } 182 fflush(dest->outfile); 183 /* Make sure we wrote the output file OK */ 184 if (ferror(dest->outfile)) 185 ERREXIT(cinfo, JERR_FILE_WRITE); 186 } 187 188 #if JPEG_LIB_VERSION >= 80 || defined(MEM_SRCDST_SUPPORTED) 189 METHODDEF(void) 190 term_mem_destination (j_compress_ptr cinfo) 191 { 192 my_mem_dest_ptr dest = (my_mem_dest_ptr) cinfo->dest; 193 194 *dest->outbuffer = dest->buffer; 195 *dest->outsize = (unsigned long)(dest->bufsize - dest->pub.free_in_buffer); 196 } 197 #endif 198 199 200 /* 201 * Prepare for output to a stdio stream. 202 * The caller must have already opened the stream, and is responsible 203 * for closing it after finishing compression. 204 */ 205 206 GLOBAL(void) 207 jpeg_stdio_dest (j_compress_ptr cinfo, FILE *outfile) 208 { 209 my_dest_ptr dest; 210 211 /* The destination object is made permanent so that multiple JPEG images 212 * can be written to the same file without re-executing jpeg_stdio_dest. 213 */ 214 if (cinfo->dest == NULL) { /* first time for this JPEG object? */ 215 cinfo->dest = (struct jpeg_destination_mgr *) 216 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, 217 sizeof(my_destination_mgr)); 218 } else if (cinfo->dest->init_destination != init_destination) { 219 /* It is unsafe to reuse the existing destination manager unless it was 220 * created by this function. Otherwise, there is no guarantee that the 221 * opaque structure is the right size. Note that we could just create a 222 * new structure, but the old structure would not be freed until 223 * jpeg_destroy_compress() was called. 224 */ 225 ERREXIT(cinfo, JERR_BUFFER_SIZE); 226 } 227 228 dest = (my_dest_ptr) cinfo->dest; 229 dest->pub.init_destination = init_destination; 230 dest->pub.empty_output_buffer = empty_output_buffer; 231 dest->pub.term_destination = term_destination; 232 dest->outfile = outfile; 233 } 234 235 236 #if JPEG_LIB_VERSION >= 80 || defined(MEM_SRCDST_SUPPORTED) 237 /* 238 * Prepare for output to a memory buffer. 239 * The caller may supply an own initial buffer with appropriate size. 240 * Otherwise, or when the actual data output exceeds the given size, 241 * the library adapts the buffer size as necessary. 242 * The standard library functions malloc/free are used for allocating 243 * larger memory, so the buffer is available to the application after 244 * finishing compression, and then the application is responsible for 245 * freeing the requested memory. 246 * Note: An initial buffer supplied by the caller is expected to be 247 * managed by the application. The library does not free such buffer 248 * when allocating a larger buffer. 249 */ 250 251 GLOBAL(void) 252 jpeg_mem_dest (j_compress_ptr cinfo, 253 unsigned char **outbuffer, unsigned long *outsize) 254 { 255 my_mem_dest_ptr dest; 256 257 if (outbuffer == NULL || outsize == NULL) /* sanity check */ 258 ERREXIT(cinfo, JERR_BUFFER_SIZE); 259 260 /* The destination object is made permanent so that multiple JPEG images 261 * can be written to the same buffer without re-executing jpeg_mem_dest. 262 */ 263 if (cinfo->dest == NULL) { /* first time for this JPEG object? */ 264 cinfo->dest = (struct jpeg_destination_mgr *) 265 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, 266 sizeof(my_mem_destination_mgr)); 267 } else if (cinfo->dest->init_destination != init_mem_destination) { 268 /* It is unsafe to reuse the existing destination manager unless it was 269 * created by this function. 270 */ 271 ERREXIT(cinfo, JERR_BUFFER_SIZE); 272 } 273 274 dest = (my_mem_dest_ptr) cinfo->dest; 275 dest->pub.init_destination = init_mem_destination; 276 dest->pub.empty_output_buffer = empty_mem_output_buffer; 277 dest->pub.term_destination = term_mem_destination; 278 dest->outbuffer = outbuffer; 279 dest->outsize = outsize; 280 dest->newbuffer = NULL; 281 282 if (*outbuffer == NULL || *outsize == 0) { 283 /* Allocate initial buffer */ 284 dest->newbuffer = *outbuffer = (unsigned char *) malloc(OUTPUT_BUF_SIZE); 285 if (dest->newbuffer == NULL) 286 ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, 10); 287 *outsize = OUTPUT_BUF_SIZE; 288 } 289 290 dest->pub.next_output_byte = dest->buffer = *outbuffer; 291 dest->pub.free_in_buffer = dest->bufsize = *outsize; 292 } 293 #endif 294