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