jdatadst-tj.c revision b5f2e450acbbae79c792f0ea5b47644fd2290a31
1/* 2 * jdatadst-tj.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 * Modifications: 8 * Copyright (C) 2011, D. R. Commander. 9 * For conditions of distribution and use, see the accompanying README file. 10 * 11 * This file contains compression data destination routines for the case of 12 * emitting JPEG data to memory or to a file (or any stdio stream). 13 * While these routines are sufficient for most applications, 14 * some will want to use a different destination manager. 15 * IMPORTANT: we assume that fwrite() will correctly transcribe an array of 16 * JOCTETs into 8-bit-wide elements on external storage. If char is wider 17 * than 8 bits on your machine, you may need to do some tweaking. 18 */ 19 20/* this is not a core library module, so it doesn't define JPEG_INTERNALS */ 21#include "jinclude.h" 22#include "jpeglib.h" 23#include "jerror.h" 24 25#ifndef HAVE_STDLIB_H /* <stdlib.h> should declare malloc(),free() */ 26extern void * malloc JPP((size_t size)); 27extern void free JPP((void *ptr)); 28#endif 29 30 31#define OUTPUT_BUF_SIZE 4096 /* choose an efficiently fwrite'able size */ 32 33 34/* Expanded data destination object for memory output */ 35 36typedef struct { 37 struct jpeg_destination_mgr pub; /* public fields */ 38 39 unsigned char ** outbuffer; /* target buffer */ 40 unsigned long * outsize; 41 unsigned char * newbuffer; /* newly allocated buffer */ 42 JOCTET * buffer; /* start of buffer */ 43 size_t bufsize; 44 boolean alloc; 45} my_mem_destination_mgr; 46 47typedef my_mem_destination_mgr * my_mem_dest_ptr; 48 49 50/* 51 * Initialize destination --- called by jpeg_start_compress 52 * before any data is actually written. 53 */ 54 55METHODDEF(void) 56init_mem_destination (j_compress_ptr cinfo) 57{ 58 /* no work necessary here */ 59} 60 61 62/* 63 * Empty the output buffer --- called whenever buffer fills up. 64 * 65 * In typical applications, this should write the entire output buffer 66 * (ignoring the current state of next_output_byte & free_in_buffer), 67 * reset the pointer & count to the start of the buffer, and return TRUE 68 * indicating that the buffer has been dumped. 69 * 70 * In applications that need to be able to suspend compression due to output 71 * overrun, a FALSE return indicates that the buffer cannot be emptied now. 72 * In this situation, the compressor will return to its caller (possibly with 73 * an indication that it has not accepted all the supplied scanlines). The 74 * application should resume compression after it has made more room in the 75 * output buffer. Note that there are substantial restrictions on the use of 76 * suspension --- see the documentation. 77 * 78 * When suspending, the compressor will back up to a convenient restart point 79 * (typically the start of the current MCU). next_output_byte & free_in_buffer 80 * indicate where the restart point will be if the current call returns FALSE. 81 * Data beyond this point will be regenerated after resumption, so do not 82 * write it out when emptying the buffer externally. 83 */ 84 85METHODDEF(boolean) 86empty_mem_output_buffer (j_compress_ptr cinfo) 87{ 88 size_t nextsize; 89 JOCTET * nextbuffer; 90 my_mem_dest_ptr dest = (my_mem_dest_ptr) cinfo->dest; 91 92 if (!dest->alloc) ERREXIT(cinfo, JERR_BUFFER_SIZE); 93 94 /* Try to allocate new buffer with double size */ 95 nextsize = dest->bufsize * 2; 96 nextbuffer = (JOCTET *) malloc(nextsize); 97 98 if (nextbuffer == NULL) 99 ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, 10); 100 101 MEMCOPY(nextbuffer, dest->buffer, dest->bufsize); 102 103 if (dest->newbuffer != NULL) 104 free(dest->newbuffer); 105 106 dest->newbuffer = nextbuffer; 107 108 dest->pub.next_output_byte = nextbuffer + dest->bufsize; 109 dest->pub.free_in_buffer = dest->bufsize; 110 111 dest->buffer = nextbuffer; 112 dest->bufsize = nextsize; 113 114 return TRUE; 115} 116 117 118/* 119 * Terminate destination --- called by jpeg_finish_compress 120 * after all data has been written. Usually needs to flush buffer. 121 * 122 * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding 123 * application must deal with any cleanup that should happen even 124 * for error exit. 125 */ 126 127METHODDEF(void) 128term_mem_destination (j_compress_ptr cinfo) 129{ 130 my_mem_dest_ptr dest = (my_mem_dest_ptr) cinfo->dest; 131 132 if(dest->alloc) *dest->outbuffer = dest->buffer; 133 *dest->outsize = (unsigned long)(dest->bufsize - dest->pub.free_in_buffer); 134} 135 136 137/* 138 * Prepare for output to a memory buffer. 139 * The caller may supply an own initial buffer with appropriate size. 140 * Otherwise, or when the actual data output exceeds the given size, 141 * the library adapts the buffer size as necessary. 142 * The standard library functions malloc/free are used for allocating 143 * larger memory, so the buffer is available to the application after 144 * finishing compression, and then the application is responsible for 145 * freeing the requested memory. 146 */ 147 148GLOBAL(void) 149jpeg_mem_dest_tj (j_compress_ptr cinfo, 150 unsigned char ** outbuffer, unsigned long * outsize, 151 boolean alloc) 152{ 153 my_mem_dest_ptr dest; 154 155 if (outbuffer == NULL || outsize == NULL) /* sanity check */ 156 ERREXIT(cinfo, JERR_BUFFER_SIZE); 157 158 /* The destination object is made permanent so that multiple JPEG images 159 * can be written to the same buffer without re-executing jpeg_mem_dest. 160 */ 161 if (cinfo->dest == NULL) { /* first time for this JPEG object? */ 162 cinfo->dest = (struct jpeg_destination_mgr *) 163 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, 164 SIZEOF(my_mem_destination_mgr)); 165 dest = (my_mem_dest_ptr) cinfo->dest; 166 dest->newbuffer = NULL; 167 } 168 169 dest = (my_mem_dest_ptr) cinfo->dest; 170 dest->pub.init_destination = init_mem_destination; 171 dest->pub.empty_output_buffer = empty_mem_output_buffer; 172 dest->pub.term_destination = term_mem_destination; 173 dest->outbuffer = outbuffer; 174 dest->outsize = outsize; 175 dest->alloc = alloc; 176 177 if (*outbuffer == NULL || *outsize == 0) { 178 if (alloc) { 179 /* Allocate initial buffer */ 180 dest->newbuffer = *outbuffer = (unsigned char *) malloc(OUTPUT_BUF_SIZE); 181 if (dest->newbuffer == NULL) 182 ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, 10); 183 *outsize = OUTPUT_BUF_SIZE; 184 } 185 else ERREXIT(cinfo, JERR_BUFFER_SIZE); 186 } 187 188 dest->pub.next_output_byte = dest->buffer = *outbuffer; 189 dest->pub.free_in_buffer = dest->bufsize = *outsize; 190} 191