Path: blob/master/thirdparty/libjpeg-turbo/src/jdatadst.c
9904 views
/*1* jdatadst.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) 2013, 2016, 2022, 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#include "jinclude.h"22#include "jpeglib.h"23#include "jerror.h"242526/* Expanded data destination object for stdio output */2728typedef struct {29struct jpeg_destination_mgr pub; /* public fields */3031FILE *outfile; /* target stream */32JOCTET *buffer; /* start of buffer */33} my_destination_mgr;3435typedef my_destination_mgr *my_dest_ptr;3637#define OUTPUT_BUF_SIZE 4096 /* choose an efficiently fwrite'able size */383940/* Expanded data destination object for memory output */4142typedef struct {43struct jpeg_destination_mgr pub; /* public fields */4445unsigned char **outbuffer; /* target buffer */46unsigned long *outsize;47unsigned char *newbuffer; /* newly allocated buffer */48JOCTET *buffer; /* start of buffer */49size_t bufsize;50} my_mem_destination_mgr;5152typedef my_mem_destination_mgr *my_mem_dest_ptr;535455/*56* Initialize destination --- called by jpeg_start_compress57* before any data is actually written.58*/5960METHODDEF(void)61init_destination(j_compress_ptr cinfo)62{63my_dest_ptr dest = (my_dest_ptr)cinfo->dest;6465/* Allocate the output buffer --- it will be released when done with image */66dest->buffer = (JOCTET *)67(*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,68OUTPUT_BUF_SIZE * sizeof(JOCTET));6970dest->pub.next_output_byte = dest->buffer;71dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;72}7374METHODDEF(void)75init_mem_destination(j_compress_ptr cinfo)76{77/* no work necessary here */78}798081/*82* Empty the output buffer --- called whenever buffer fills up.83*84* In typical applications, this should write the entire output buffer85* (ignoring the current state of next_output_byte & free_in_buffer),86* reset the pointer & count to the start of the buffer, and return TRUE87* indicating that the buffer has been dumped.88*89* In applications that need to be able to suspend compression due to output90* overrun, a FALSE return indicates that the buffer cannot be emptied now.91* In this situation, the compressor will return to its caller (possibly with92* an indication that it has not accepted all the supplied scanlines). The93* application should resume compression after it has made more room in the94* output buffer. Note that there are substantial restrictions on the use of95* suspension --- see the documentation.96*97* When suspending, the compressor will back up to a convenient restart point98* (typically the start of the current MCU). next_output_byte & free_in_buffer99* indicate where the restart point will be if the current call returns FALSE.100* Data beyond this point will be regenerated after resumption, so do not101* write it out when emptying the buffer externally.102*/103104METHODDEF(boolean)105empty_output_buffer(j_compress_ptr cinfo)106{107my_dest_ptr dest = (my_dest_ptr)cinfo->dest;108109if (fwrite(dest->buffer, 1, OUTPUT_BUF_SIZE, dest->outfile) !=110(size_t)OUTPUT_BUF_SIZE)111ERREXIT(cinfo, JERR_FILE_WRITE);112113dest->pub.next_output_byte = dest->buffer;114dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;115116return TRUE;117}118119METHODDEF(boolean)120empty_mem_output_buffer(j_compress_ptr cinfo)121{122size_t nextsize;123JOCTET *nextbuffer;124my_mem_dest_ptr dest = (my_mem_dest_ptr)cinfo->dest;125126/* Try to allocate new buffer with double size */127nextsize = dest->bufsize * 2;128nextbuffer = (JOCTET *)malloc(nextsize);129130if (nextbuffer == NULL)131ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, 10);132133memcpy(nextbuffer, dest->buffer, dest->bufsize);134135free(dest->newbuffer);136137dest->newbuffer = nextbuffer;138139dest->pub.next_output_byte = nextbuffer + dest->bufsize;140dest->pub.free_in_buffer = dest->bufsize;141142dest->buffer = nextbuffer;143dest->bufsize = nextsize;144145return TRUE;146}147148149/*150* Terminate destination --- called by jpeg_finish_compress151* after all data has been written. Usually needs to flush buffer.152*153* NB: *not* called by jpeg_abort or jpeg_destroy; surrounding154* application must deal with any cleanup that should happen even155* for error exit.156*/157158METHODDEF(void)159term_destination(j_compress_ptr cinfo)160{161my_dest_ptr dest = (my_dest_ptr)cinfo->dest;162size_t datacount = OUTPUT_BUF_SIZE - dest->pub.free_in_buffer;163164/* Write any data remaining in the buffer */165if (datacount > 0) {166if (fwrite(dest->buffer, 1, datacount, dest->outfile) != datacount)167ERREXIT(cinfo, JERR_FILE_WRITE);168}169fflush(dest->outfile);170/* Make sure we wrote the output file OK */171if (ferror(dest->outfile))172ERREXIT(cinfo, JERR_FILE_WRITE);173}174175METHODDEF(void)176term_mem_destination(j_compress_ptr cinfo)177{178my_mem_dest_ptr dest = (my_mem_dest_ptr)cinfo->dest;179180*dest->outbuffer = dest->buffer;181*dest->outsize = (unsigned long)(dest->bufsize - dest->pub.free_in_buffer);182}183184185/*186* Prepare for output to a stdio stream.187* The caller must have already opened the stream, and is responsible188* for closing it after finishing compression.189*/190191GLOBAL(void)192jpeg_stdio_dest(j_compress_ptr cinfo, FILE *outfile)193{194my_dest_ptr dest;195196/* The destination object is made permanent so that multiple JPEG images197* can be written to the same file without re-executing jpeg_stdio_dest.198*/199if (cinfo->dest == NULL) { /* first time for this JPEG object? */200cinfo->dest = (struct jpeg_destination_mgr *)201(*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_PERMANENT,202sizeof(my_destination_mgr));203} else if (cinfo->dest->init_destination != init_destination) {204/* It is unsafe to reuse the existing destination manager unless it was205* created by this function. Otherwise, there is no guarantee that the206* opaque structure is the right size. Note that we could just create a207* new structure, but the old structure would not be freed until208* jpeg_destroy_compress() was called.209*/210ERREXIT(cinfo, JERR_BUFFER_SIZE);211}212213dest = (my_dest_ptr)cinfo->dest;214dest->pub.init_destination = init_destination;215dest->pub.empty_output_buffer = empty_output_buffer;216dest->pub.term_destination = term_destination;217dest->outfile = outfile;218}219220221/*222* Prepare for output to a memory buffer.223* The caller may supply an own initial buffer with appropriate size.224* Otherwise, or when the actual data output exceeds the given size,225* the library adapts the buffer size as necessary.226* The standard library functions malloc/free are used for allocating227* larger memory, so the buffer is available to the application after228* finishing compression, and then the application is responsible for229* freeing the requested memory.230* Note: An initial buffer supplied by the caller is expected to be231* managed by the application. The library does not free such buffer232* when allocating a larger buffer.233*/234235GLOBAL(void)236jpeg_mem_dest(j_compress_ptr cinfo, unsigned char **outbuffer,237unsigned long *outsize)238{239my_mem_dest_ptr dest;240241if (outbuffer == NULL || outsize == NULL) /* sanity check */242ERREXIT(cinfo, JERR_BUFFER_SIZE);243244/* The destination object is made permanent so that multiple JPEG images245* can be written to the same buffer without re-executing jpeg_mem_dest.246*/247if (cinfo->dest == NULL) { /* first time for this JPEG object? */248cinfo->dest = (struct jpeg_destination_mgr *)249(*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_PERMANENT,250sizeof(my_mem_destination_mgr));251} else if (cinfo->dest->init_destination != init_mem_destination) {252/* It is unsafe to reuse the existing destination manager unless it was253* created by this function.254*/255ERREXIT(cinfo, JERR_BUFFER_SIZE);256}257258dest = (my_mem_dest_ptr)cinfo->dest;259dest->pub.init_destination = init_mem_destination;260dest->pub.empty_output_buffer = empty_mem_output_buffer;261dest->pub.term_destination = term_mem_destination;262dest->outbuffer = outbuffer;263dest->outsize = outsize;264dest->newbuffer = NULL;265266if (*outbuffer == NULL || *outsize == 0) {267/* Allocate initial buffer */268dest->newbuffer = *outbuffer = (unsigned char *)malloc(OUTPUT_BUF_SIZE);269if (dest->newbuffer == NULL)270ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, 10);271*outsize = OUTPUT_BUF_SIZE;272}273274dest->pub.next_output_byte = dest->buffer = *outbuffer;275dest->pub.free_in_buffer = dest->bufsize = *outsize;276}277278279