Home | History | Annotate | Download | only in image-encoders
      1 /*
      2  * Copyright (C) 2009 Torch Mobile, Inc. All rights reserved.
      3  * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved.
      4  *
      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.
      9  *
     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.
     14  *
     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.
     19  */
     20 
     21 
     22 #include "config.h"
     23 #include "JPEGImageEncoder.h"
     24 
     25 #include "IntSize.h"
     26 // FIXME: jpeglib.h requires stdio.h to be included first for FILE
     27 #include <stdio.h>
     28 #include "jpeglib.h"
     29 #include <setjmp.h>
     30 
     31 namespace WebCore {
     32 
     33 class JPEGDestinationManager : public jpeg_destination_mgr {
     34 public:
     35     explicit JPEGDestinationManager(Vector<char>& toDump)
     36         : m_dump(toDump)
     37     {
     38         // Zero base class memory.
     39         jpeg_destination_mgr* base = this;
     40         memset(base, 0, sizeof(jpeg_destination_mgr));
     41     }
     42     Vector<char> m_buffer;
     43     Vector<char>& m_dump;
     44 };
     45 
     46 class JPEGCompressErrorMgr : public jpeg_error_mgr {
     47 public:
     48     JPEGCompressErrorMgr()
     49     {
     50         // Zero memory
     51         memset(this, 0, sizeof(JPEGCompressErrorMgr));
     52     }
     53 
     54     jmp_buf m_setjmpBuffer;
     55 };
     56 
     57 static void jpegInitializeDestination(j_compress_ptr compressData)
     58 {
     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();
     63 }
     64 
     65 static boolean jpegEmptyOutputBuffer(j_compress_ptr compressData)
     66 {
     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();
     71     return TRUE;
     72 }
     73 
     74 static void jpegTerminateDestination(j_compress_ptr compressData)
     75 {
     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);
     78 }
     79 
     80 static void jpegErrorExit(j_common_ptr compressData)
     81 {
     82     JPEGCompressErrorMgr* err = static_cast<JPEGCompressErrorMgr*>(compressData->err);
     83     longjmp(err->m_setjmpBuffer, -1);
     84 }
     85 
     86 bool compressRGBABigEndianToJPEG(unsigned char* rgbaBigEndianData, const IntSize& size, Vector<char>& jpegData)
     87 {
     88     struct jpeg_compress_struct compressData = { 0 };
     89     JPEGCompressErrorMgr err;
     90     compressData.err = jpeg_std_error(&err);
     91     err.error_exit = jpegErrorExit;
     92 
     93     jpeg_create_compress(&compressData);
     94 
     95     JPEGDestinationManager dest(jpegData);
     96     compressData.dest = &dest;
     97     dest.init_destination = jpegInitializeDestination;
     98     dest.empty_output_buffer = jpegEmptyOutputBuffer;
     99     dest.term_destination = jpegTerminateDestination;
    100 
    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);
    107 
    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;
    110 
    111     if (setjmp(err.m_setjmpBuffer))
    112         return false;
    113 
    114     jpeg_start_compress(&compressData, TRUE);
    115     rowBuffer.resize(compressData.image_width * 3);
    116 
    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
    126         }
    127         output = rowBuffer.data();
    128         jpeg_write_scanlines(&compressData, &output, 1);
    129     }
    130 
    131     jpeg_finish_compress(&compressData);
    132     return true;
    133 }
    134 
    135 } // namespace WebCore
    136