1 /* Copyright 2015 The TensorFlow Authors. All Rights Reserved. 2 3 Licensed under the Apache License, Version 2.0 (the "License"); 4 you may not use this file except in compliance with the License. 5 You may obtain a copy of the License at 6 7 http://www.apache.org/licenses/LICENSE-2.0 8 9 Unless required by applicable law or agreed to in writing, software 10 distributed under the License is distributed on an "AS IS" BASIS, 11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 See the License for the specific language governing permissions and 13 limitations under the License. 14 ==============================================================================*/ 15 16 // This file implements a memory destination for libjpeg 17 // The design is very similar to jdatadst.c in libjpeg 18 // These functions are not meant to be used directly, see jpeg_mem.h instead. 19 // We are filling out stubs required by jpeglib, those stubs are private to 20 // the implementation, we are just making available JPGMemSrc, JPGMemDest 21 22 #include "tensorflow/core/lib/jpeg/jpeg_handle.h" 23 24 #include <setjmp.h> 25 #include <stddef.h> 26 27 #include "tensorflow/core/platform/logging.h" 28 29 namespace tensorflow { 30 namespace jpeg { 31 32 void CatchError(j_common_ptr cinfo) { 33 (*cinfo->err->output_message)(cinfo); 34 jmp_buf *jpeg_jmpbuf = reinterpret_cast<jmp_buf *>(cinfo->client_data); 35 jpeg_destroy(cinfo); 36 longjmp(*jpeg_jmpbuf, 1); 37 } 38 39 // ***************************************************************************** 40 // ***************************************************************************** 41 // ***************************************************************************** 42 // Destination functions 43 44 // ----------------------------------------------------------------------------- 45 void MemInitDestination(j_compress_ptr cinfo) { 46 MemDestMgr *dest = reinterpret_cast<MemDestMgr *>(cinfo->dest); 47 VLOG(1) << "Initializing buffer=" << dest->bufsize << " bytes"; 48 dest->pub.next_output_byte = dest->buffer; 49 dest->pub.free_in_buffer = dest->bufsize; 50 dest->datacount = 0; 51 if (dest->dest) { 52 dest->dest->clear(); 53 } 54 } 55 56 // ----------------------------------------------------------------------------- 57 boolean MemEmptyOutputBuffer(j_compress_ptr cinfo) { 58 MemDestMgr *dest = reinterpret_cast<MemDestMgr *>(cinfo->dest); 59 VLOG(1) << "Writing " << dest->bufsize << " bytes"; 60 if (dest->dest) { 61 dest->dest->append(reinterpret_cast<char *>(dest->buffer), dest->bufsize); 62 } 63 dest->pub.next_output_byte = dest->buffer; 64 dest->pub.free_in_buffer = dest->bufsize; 65 return TRUE; 66 } 67 68 // ----------------------------------------------------------------------------- 69 void MemTermDestination(j_compress_ptr cinfo) { 70 MemDestMgr *dest = reinterpret_cast<MemDestMgr *>(cinfo->dest); 71 VLOG(1) << "Writing " << dest->bufsize - dest->pub.free_in_buffer << " bytes"; 72 if (dest->dest) { 73 dest->dest->append(reinterpret_cast<char *>(dest->buffer), 74 dest->bufsize - dest->pub.free_in_buffer); 75 VLOG(1) << "Total size= " << dest->dest->size(); 76 } 77 dest->datacount = dest->bufsize - dest->pub.free_in_buffer; 78 } 79 80 // ----------------------------------------------------------------------------- 81 void SetDest(j_compress_ptr cinfo, void *buffer, int bufsize) { 82 SetDest(cinfo, buffer, bufsize, nullptr); 83 } 84 85 // ----------------------------------------------------------------------------- 86 void SetDest(j_compress_ptr cinfo, void *buffer, int bufsize, 87 string *destination) { 88 MemDestMgr *dest; 89 if (cinfo->dest == nullptr) { 90 cinfo->dest = reinterpret_cast<struct jpeg_destination_mgr *>( 91 (*cinfo->mem->alloc_small)(reinterpret_cast<j_common_ptr>(cinfo), 92 JPOOL_PERMANENT, sizeof(MemDestMgr))); 93 } 94 95 dest = reinterpret_cast<MemDestMgr *>(cinfo->dest); 96 dest->bufsize = bufsize; 97 dest->buffer = static_cast<JOCTET *>(buffer); 98 dest->dest = destination; 99 dest->pub.init_destination = MemInitDestination; 100 dest->pub.empty_output_buffer = MemEmptyOutputBuffer; 101 dest->pub.term_destination = MemTermDestination; 102 } 103 104 // ***************************************************************************** 105 // ***************************************************************************** 106 // ***************************************************************************** 107 // Source functions 108 109 // ----------------------------------------------------------------------------- 110 void MemInitSource(j_decompress_ptr cinfo) { 111 MemSourceMgr *src = reinterpret_cast<MemSourceMgr *>(cinfo->src); 112 src->pub.next_input_byte = src->data; 113 src->pub.bytes_in_buffer = src->datasize; 114 } 115 116 // ----------------------------------------------------------------------------- 117 // We emulate the same error-handling as fill_input_buffer() from jdatasrc.c, 118 // for coherency's sake. 119 boolean MemFillInputBuffer(j_decompress_ptr cinfo) { 120 static const JOCTET kEOIBuffer[2] = {0xff, JPEG_EOI}; 121 MemSourceMgr *src = reinterpret_cast<MemSourceMgr *>(cinfo->src); 122 if (src->pub.bytes_in_buffer == 0 && src->pub.next_input_byte == src->data) { 123 // empty file -> treated as an error. 124 ERREXIT(cinfo, JERR_INPUT_EMPTY); 125 return FALSE; 126 } else if (src->pub.bytes_in_buffer) { 127 // if there's still some data left, it's probably corrupted 128 return src->try_recover_truncated_jpeg ? TRUE : FALSE; 129 } else if (src->pub.next_input_byte != kEOIBuffer && 130 src->try_recover_truncated_jpeg) { 131 // In an attempt to recover truncated files, we insert a fake EOI 132 WARNMS(cinfo, JWRN_JPEG_EOF); 133 src->pub.next_input_byte = kEOIBuffer; 134 src->pub.bytes_in_buffer = 2; 135 return TRUE; 136 } else { 137 // We already inserted a fake EOI and it wasn't enough, so this time 138 // it's really an error. 139 ERREXIT(cinfo, JERR_FILE_READ); 140 return FALSE; 141 } 142 } 143 144 // ----------------------------------------------------------------------------- 145 void MemTermSource(j_decompress_ptr cinfo) {} 146 147 // ----------------------------------------------------------------------------- 148 void MemSkipInputData(j_decompress_ptr cinfo, long jump) { 149 MemSourceMgr *src = reinterpret_cast<MemSourceMgr *>(cinfo->src); 150 if (jump < 0) { 151 return; 152 } 153 if (jump > src->pub.bytes_in_buffer) { 154 src->pub.bytes_in_buffer = 0; 155 (void)MemFillInputBuffer(cinfo); // warn with a fake EOI or error 156 } else { 157 src->pub.bytes_in_buffer -= jump; 158 src->pub.next_input_byte += jump; 159 } 160 } 161 162 // ----------------------------------------------------------------------------- 163 void SetSrc(j_decompress_ptr cinfo, const void *data, 164 unsigned long int datasize, bool try_recover_truncated_jpeg) { 165 MemSourceMgr *src; 166 167 cinfo->src = reinterpret_cast<struct jpeg_source_mgr *>( 168 (*cinfo->mem->alloc_small)(reinterpret_cast<j_common_ptr>(cinfo), 169 JPOOL_PERMANENT, sizeof(MemSourceMgr))); 170 171 src = reinterpret_cast<MemSourceMgr *>(cinfo->src); 172 src->pub.init_source = MemInitSource; 173 src->pub.fill_input_buffer = MemFillInputBuffer; 174 src->pub.skip_input_data = MemSkipInputData; 175 src->pub.resync_to_restart = jpeg_resync_to_restart; 176 src->pub.term_source = MemTermSource; 177 src->data = reinterpret_cast<const unsigned char *>(data); 178 src->datasize = datasize; 179 src->pub.bytes_in_buffer = 0; 180 src->pub.next_input_byte = nullptr; 181 src->try_recover_truncated_jpeg = try_recover_truncated_jpeg; 182 } 183 184 } // namespace jpeg 185 } // namespace tensorflow 186