jfifcontainer.cpp
00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <setjmp.h>
00023 #include <cstdio>
00024
00025 namespace JPEG {
00026
00027
00028
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 "debug.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
00065
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
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
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 }