Path: blob/master/thirdparty/libjpeg-turbo/src/jdatadst-tj.c
9904 views
/*1* jdatadst-tj.c2*3* This file was part of the Independent JPEG Group's software:4* Copyright (C) 1994-1996, Thomas G. Lane.5* Modified 2009-2012 by Guido Vollbeding.6* libjpeg-turbo Modifications:7* Copyright (C) 2011, 2014, 2016, 2019, 2022-2023, D. R. Commander.8* For conditions of distribution and use, see the accompanying README.ijg9* file.10*11* This file contains compression data destination routines for the case of12* 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 of16* JOCTETs into 8-bit-wide elements on external storage. If char is wider17* than 8 bits on your machine, you may need to do some tweaking.18*/1920/* this is not a core library module, so it doesn't define JPEG_INTERNALS */21#define JPEG_INTERNALS22#include "jinclude.h"23#include "jpeglib.h"24#include "jerror.h"2526void jpeg_mem_dest_tj(j_compress_ptr cinfo, unsigned char **outbuffer,27size_t *outsize, boolean alloc);282930#define OUTPUT_BUF_SIZE 4096 /* choose an efficiently fwrite'able size */313233/* Expanded data destination object for memory output */3435typedef struct {36struct jpeg_destination_mgr pub; /* public fields */3738unsigned char **outbuffer; /* target buffer */39size_t *outsize;40unsigned char *newbuffer; /* newly allocated buffer */41JOCTET *buffer; /* start of buffer */42size_t bufsize;43boolean alloc;44} my_mem_destination_mgr;4546typedef my_mem_destination_mgr *my_mem_dest_ptr;474849/*50* Initialize destination --- called by jpeg_start_compress51* before any data is actually written.52*/5354METHODDEF(void)55init_mem_destination(j_compress_ptr cinfo)56{57/* no work necessary here */58}596061/*62* Empty the output buffer --- called whenever buffer fills up.63*64* In typical applications, this should write the entire output buffer65* (ignoring the current state of next_output_byte & free_in_buffer),66* reset the pointer & count to the start of the buffer, and return TRUE67* indicating that the buffer has been dumped.68*69* In applications that need to be able to suspend compression due to output70* overrun, a FALSE return indicates that the buffer cannot be emptied now.71* In this situation, the compressor will return to its caller (possibly with72* an indication that it has not accepted all the supplied scanlines). The73* application should resume compression after it has made more room in the74* output buffer. Note that there are substantial restrictions on the use of75* suspension --- see the documentation.76*77* When suspending, the compressor will back up to a convenient restart point78* (typically the start of the current MCU). next_output_byte & free_in_buffer79* indicate where the restart point will be if the current call returns FALSE.80* Data beyond this point will be regenerated after resumption, so do not81* write it out when emptying the buffer externally.82*/8384METHODDEF(boolean)85empty_mem_output_buffer(j_compress_ptr cinfo)86{87size_t nextsize;88JOCTET *nextbuffer;89my_mem_dest_ptr dest = (my_mem_dest_ptr)cinfo->dest;9091if (!dest->alloc) ERREXIT(cinfo, JERR_BUFFER_SIZE);9293/* Try to allocate new buffer with double size */94nextsize = dest->bufsize * 2;95nextbuffer = (JOCTET *)MALLOC(nextsize);9697if (nextbuffer == NULL)98ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, 10);99100memcpy(nextbuffer, dest->buffer, dest->bufsize);101102free(dest->newbuffer);103104dest->newbuffer = nextbuffer;105106dest->pub.next_output_byte = nextbuffer + dest->bufsize;107dest->pub.free_in_buffer = dest->bufsize;108109dest->buffer = nextbuffer;110dest->bufsize = nextsize;111112return TRUE;113}114115116/*117* Terminate destination --- called by jpeg_finish_compress118* after all data has been written. Usually needs to flush buffer.119*120* NB: *not* called by jpeg_abort or jpeg_destroy; surrounding121* application must deal with any cleanup that should happen even122* for error exit.123*/124125METHODDEF(void)126term_mem_destination(j_compress_ptr cinfo)127{128my_mem_dest_ptr dest = (my_mem_dest_ptr)cinfo->dest;129130if (dest->alloc) *dest->outbuffer = dest->buffer;131*dest->outsize = dest->bufsize - dest->pub.free_in_buffer;132}133134135/*136* Prepare for output to a memory buffer.137* The caller may supply an own initial buffer with appropriate size.138* Otherwise, or when the actual data output exceeds the given size,139* the library adapts the buffer size as necessary.140* The standard library functions malloc/free are used for allocating141* larger memory, so the buffer is available to the application after142* finishing compression, and then the application is responsible for143* freeing the requested memory.144*/145146GLOBAL(void)147jpeg_mem_dest_tj(j_compress_ptr cinfo, unsigned char **outbuffer,148size_t *outsize, boolean alloc)149{150boolean reused = FALSE;151my_mem_dest_ptr dest;152153if (outbuffer == NULL || outsize == NULL) /* sanity check */154ERREXIT(cinfo, JERR_BUFFER_SIZE);155156/* The destination object is made permanent so that multiple JPEG images157* can be written to the same buffer without re-executing jpeg_mem_dest.158*/159if (cinfo->dest == NULL) { /* first time for this JPEG object? */160cinfo->dest = (struct jpeg_destination_mgr *)161(*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_PERMANENT,162sizeof(my_mem_destination_mgr));163dest = (my_mem_dest_ptr)cinfo->dest;164dest->newbuffer = NULL;165dest->buffer = NULL;166} else if (cinfo->dest->init_destination != init_mem_destination) {167/* It is unsafe to reuse the existing destination manager unless it was168* created by this function.169*/170ERREXIT(cinfo, JERR_BUFFER_SIZE);171}172173dest = (my_mem_dest_ptr)cinfo->dest;174dest->pub.init_destination = init_mem_destination;175dest->pub.empty_output_buffer = empty_mem_output_buffer;176dest->pub.term_destination = term_mem_destination;177if (dest->buffer == *outbuffer && *outbuffer != NULL && alloc)178reused = TRUE;179dest->outbuffer = outbuffer;180dest->outsize = outsize;181dest->alloc = alloc;182183if (*outbuffer == NULL || *outsize == 0) {184if (alloc) {185/* Allocate initial buffer */186dest->newbuffer = *outbuffer = (unsigned char *)MALLOC(OUTPUT_BUF_SIZE);187if (dest->newbuffer == NULL)188ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, 10);189*outsize = OUTPUT_BUF_SIZE;190} else191ERREXIT(cinfo, JERR_BUFFER_SIZE);192}193194dest->pub.next_output_byte = dest->buffer = *outbuffer;195if (!reused)196dest->bufsize = *outsize;197dest->pub.free_in_buffer = dest->bufsize;198}199200201