libopenraw
|
00001 /* 00002 * libopenraw - jfifcontainer.h 00003 * 00004 * Copyright (C) 2006-2007 Hubert Figuiere 00005 * 00006 * This library is free software: you can redistribute it and/or 00007 * modify it under the terms of the GNU Lesser General Public License 00008 * as published by the Free Software Foundation, either version 3 of 00009 * the License, or (at your option) any later version. 00010 * 00011 * This library is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00014 * Lesser General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU Lesser General Public 00017 * License along with this library. If not, see 00018 * <http://www.gnu.org/licenses/>. 00019 */ 00020 00021 00022 #include <setjmp.h> 00023 #include <cstdio> 00024 00025 namespace JPEG { 00026 /* 00027 * The extern "C" below is REQUIRED for libjpeg-mmx-dev 00028 * as found on debian because some people have this installed. 00029 */ 00030 extern "C" { 00031 #include <jpeglib.h> 00032 } 00033 } 00034 00035 #include <string.h> 00036 #include <libopenraw++/bitmapdata.h> 00037 #include "io/stream.h" 00038 #include "trace.h" 00039 #include "jfifcontainer.h" 00040 00041 namespace OpenRaw { 00042 00043 using namespace Debug; 00044 00045 namespace Internals { 00046 00049 #define BUF_SIZE 1024 00050 00051 typedef struct { 00052 struct JPEG::jpeg_source_mgr pub; 00053 JFIFContainer * self; 00054 off_t offset; 00055 JPEG::JOCTET* buf; 00056 } jpeg_src_t; 00057 00058 JFIFContainer::JFIFContainer(IO::Stream *_file, off_t offset) 00059 : RawContainer(_file, offset), 00060 m_cinfo(), m_jerr(), 00061 m_headerLoaded(false) 00062 { 00063 setEndian(ENDIAN_BIG); 00064 /* this is a hack because jpeg_create_decompress is 00065 * implemented as a Macro 00066 */ 00067 using namespace JPEG; 00068 00069 m_cinfo.err = JPEG::jpeg_std_error(&m_jerr); 00070 m_jerr.error_exit = &j_error_exit; 00071 JPEG::jpeg_create_decompress(&m_cinfo); 00072 00073 /* inspired by jdatasrc.c */ 00074 00075 jpeg_src_t *src = (jpeg_src_t *) 00076 (*m_cinfo.mem->alloc_small)((JPEG::j_common_ptr)&m_cinfo, 00077 JPOOL_PERMANENT, 00078 sizeof(jpeg_src_t)); 00079 m_cinfo.src = (JPEG::jpeg_source_mgr*)src; 00080 src->pub.init_source = j_init_source; 00081 src->pub.fill_input_buffer = j_fill_input_buffer; 00082 src->pub.skip_input_data = j_skip_input_data; 00083 src->pub.resync_to_restart = JPEG::jpeg_resync_to_restart; 00084 src->pub.term_source = j_term_source; 00085 src->self = this; 00086 src->pub.bytes_in_buffer = 0; 00087 src->pub.next_input_byte = NULL; 00088 src->buf = (JPEG::JOCTET*)(*m_cinfo.mem->alloc_small) 00089 ((JPEG::j_common_ptr)&m_cinfo, 00090 JPOOL_PERMANENT, 00091 BUF_SIZE * sizeof(JPEG::JOCTET)); 00092 } 00093 00094 JFIFContainer::~JFIFContainer() 00095 { 00096 JPEG::jpeg_destroy_decompress(&m_cinfo); 00097 } 00098 00099 00100 bool JFIFContainer::getDimensions(uint32_t &x, uint32_t &y) 00101 { 00102 if(!m_headerLoaded) { 00103 if (_loadHeader() == 0) { 00104 Trace(DEBUG1) << "load header failed\n"; 00105 return false; 00106 } 00107 } 00108 x = m_cinfo.output_width; 00109 y = m_cinfo.output_height; 00110 return true; 00111 } 00112 00113 00114 bool JFIFContainer::getDecompressedData(BitmapData &data) 00115 { 00116 if(!m_headerLoaded) { 00117 if (_loadHeader() == 0) { 00118 Trace(DEBUG1) << "load header failed\n"; 00119 return false; 00120 } 00121 } 00122 if (::setjmp(m_jpegjmp) != 0) { 00123 return false; 00124 } 00125 JPEG::jpeg_start_decompress(&m_cinfo); 00126 int row_size = m_cinfo.output_width * m_cinfo.output_components; 00127 char *dataPtr = (char*)data.allocData(row_size * m_cinfo.output_height); 00128 char *currentPtr = dataPtr; 00129 JPEG::JSAMPARRAY buffer = (*m_cinfo.mem->alloc_sarray)((JPEG::j_common_ptr)&m_cinfo, 00130 JPOOL_IMAGE, row_size, 00131 1); 00132 while (m_cinfo.output_scanline < m_cinfo.output_height) { 00133 jpeg_read_scanlines(&m_cinfo, buffer, 1); 00134 memcpy(currentPtr, buffer, row_size); 00135 currentPtr += row_size; 00136 } 00137 data.setDimensions(m_cinfo.output_width, m_cinfo.output_height); 00138 00139 JPEG::jpeg_finish_decompress(&m_cinfo); 00140 return true; 00141 } 00142 00143 00144 int JFIFContainer::_loadHeader() 00145 { 00146 int ret = 0; 00147 if (::setjmp(m_jpegjmp) == 0) { 00148 ret = JPEG::jpeg_read_header(&m_cinfo, TRUE); 00149 //Trace(DEBUG1) << "jpeg_read_header " << ret << "\n"; 00150 00151 JPEG::jpeg_calc_output_dimensions(&m_cinfo); 00152 } 00153 m_headerLoaded = (ret == 1); 00154 return ret; 00155 } 00156 00157 00158 void JFIFContainer::j_error_exit(JPEG::j_common_ptr cinfo) 00159 { 00160 (*cinfo->err->output_message) (cinfo); 00161 JFIFContainer *self = ((jpeg_src_t *)(((JPEG::j_decompress_ptr)cinfo)->src))->self; 00162 ::longjmp(self->m_jpegjmp, 1); 00163 } 00164 00165 void JFIFContainer::j_init_source(JPEG::j_decompress_ptr) 00166 { 00167 } 00168 00169 00170 JPEG::boolean 00171 JFIFContainer::j_fill_input_buffer(JPEG::j_decompress_ptr cinfo) 00172 { 00173 jpeg_src_t *src = (jpeg_src_t*)cinfo->src; 00174 JFIFContainer *self = src->self; 00175 int n = self->file()->read(src->buf, BUF_SIZE * sizeof(*src->buf)); 00176 if (n >= 0) { 00177 src->pub.next_input_byte = src->buf; 00178 src->pub.bytes_in_buffer = n; 00179 } 00180 else { 00181 src->pub.next_input_byte = NULL; 00182 src->pub.bytes_in_buffer = 0; 00183 } 00184 return TRUE; 00185 } 00186 00187 00188 void JFIFContainer::j_skip_input_data(JPEG::j_decompress_ptr cinfo, 00189 long num_bytes) 00190 { 00191 jpeg_src_t *src = (jpeg_src_t*)cinfo->src; 00192 if (num_bytes > 0) { 00193 while ((size_t)num_bytes > src->pub.bytes_in_buffer) { 00194 num_bytes -= src->pub.bytes_in_buffer; 00195 j_fill_input_buffer(cinfo); 00196 } 00197 src->pub.next_input_byte += (size_t) num_bytes; 00198 src->pub.bytes_in_buffer -= (size_t) num_bytes; 00199 } 00200 } 00201 00202 00203 void JFIFContainer::j_term_source(JPEG::j_decompress_ptr) 00204 { 00205 } 00206 00207 00208 } 00209 }