2 * Copyright (C) 2009 Torch Mobile, Inc. All rights reserved.
3 * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved.
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public License
16 * along with this library; see the file COPYING.LIB. If not, write to
17 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
23 #include "JPEGImageEncoder.h"
26 // FIXME: jpeglib.h requires stdio.h to be included first for FILE
33 class JPEGDestinationManager : public jpeg_destination_mgr {
35 explicit JPEGDestinationManager(Vector<char>& toDump)
38 // Zero base class memory.
39 jpeg_destination_mgr* base = this;
40 memset(base, 0, sizeof(jpeg_destination_mgr));
42 Vector<char> m_buffer;
46 class JPEGCompressErrorMgr : public jpeg_error_mgr {
48 JPEGCompressErrorMgr()
51 memset(this, 0, sizeof(JPEGCompressErrorMgr));
54 jmp_buf m_setjmpBuffer;
57 static void jpegInitializeDestination(j_compress_ptr compressData)
59 JPEGDestinationManager* dest = static_cast<JPEGDestinationManager*>(compressData->dest);
60 dest->m_buffer.resize(4096);
61 dest->next_output_byte = reinterpret_cast<JOCTET*>(dest->m_buffer.data());
62 dest->free_in_buffer = dest->m_buffer.size();
65 static boolean jpegEmptyOutputBuffer(j_compress_ptr compressData)
67 JPEGDestinationManager* dest = static_cast<JPEGDestinationManager*>(compressData->dest);
68 dest->m_dump.append(dest->m_buffer.data(), dest->m_buffer.size());
69 dest->next_output_byte = reinterpret_cast<JOCTET*>(dest->m_buffer.data());
70 dest->free_in_buffer = dest->m_buffer.size();
74 static void jpegTerminateDestination(j_compress_ptr compressData)
76 JPEGDestinationManager* dest = static_cast<JPEGDestinationManager*>(compressData->dest);
77 dest->m_dump.append(dest->m_buffer.data(), dest->m_buffer.size() - dest->free_in_buffer);
80 static void jpegErrorExit(j_common_ptr compressData)
82 JPEGCompressErrorMgr* err = static_cast<JPEGCompressErrorMgr*>(compressData->err);
83 longjmp(err->m_setjmpBuffer, -1);
86 bool compressRGBABigEndianToJPEG(unsigned char* rgbaBigEndianData, const IntSize& size, Vector<char>& jpegData)
88 struct jpeg_compress_struct compressData = { 0 };
89 JPEGCompressErrorMgr err;
90 compressData.err = jpeg_std_error(&err);
91 err.error_exit = jpegErrorExit;
93 jpeg_create_compress(&compressData);
95 JPEGDestinationManager dest(jpegData);
96 compressData.dest = &dest;
97 dest.init_destination = jpegInitializeDestination;
98 dest.empty_output_buffer = jpegEmptyOutputBuffer;
99 dest.term_destination = jpegTerminateDestination;
101 compressData.image_width = size.width();
102 compressData.image_height = size.height();
103 compressData.input_components = 3;
104 compressData.in_color_space = JCS_RGB;
105 jpeg_set_defaults(&compressData);
106 jpeg_set_quality(&compressData, 65, FALSE);
108 // rowBuffer must be defined here so that its destructor is always called even when "setjmp" catches an error.
109 Vector<JSAMPLE, 600 * 3> rowBuffer;
111 if (setjmp(err.m_setjmpBuffer))
114 jpeg_start_compress(&compressData, TRUE);
115 rowBuffer.resize(compressData.image_width * 3);
117 const unsigned char* pixel = rgbaBigEndianData;
118 const unsigned char* pixelEnd = pixel + compressData.image_width * compressData.image_height * 4;
119 while (pixel < pixelEnd) {
120 JSAMPLE* output = rowBuffer.data();
121 for (const unsigned char* rowEnd = pixel + compressData.image_width * 4; pixel < rowEnd;) {
122 *output++ = static_cast<JSAMPLE>(*pixel++ & 0xFF); // red
123 *output++ = static_cast<JSAMPLE>(*pixel++ & 0xFF); // green
124 *output++ = static_cast<JSAMPLE>(*pixel++ & 0xFF); // blue
125 ++pixel; // skip alpha
127 output = rowBuffer.data();
128 jpeg_write_scanlines(&compressData, &output, 1);
131 jpeg_finish_compress(&compressData);
135 } // namespace WebCore