1/* 2 * Copyright (C) 2010, 2011 Research In Motion Limited. All rights reserved. 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation; either 7 * version 2 of the License, or (at your option) any later version. 8 * 9 * This library is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Lesser General Public License for more details. 13 * 14 * You should have received a copy of the GNU Lesser General Public 15 * License along with this library; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 17 */ 18 19// Implementation notes: 20// Current implementation provides the source image size without doing a full 21// decode. It seems that libimg does not support partial decoding. 22 23#include "config.h" 24#include "JPEGImageDecoder.h" 25 26#include <errno.h> 27#include <img/img.h> 28#include <string.h> 29#include <wtf/OwnArrayPtr.h> 30#include <wtf/PassOwnPtr.h> 31 32namespace WebCore { 33 34static img_lib_t s_ilib; 35 36static inline int libInit() 37{ 38 static bool s_initialized; 39 if (s_initialized) 40 return 0; 41 42 if (img_lib_attach(&s_ilib) != IMG_ERR_OK) { 43 LOG_ERROR("Unable to attach to libimg."); 44 return -1; 45 } 46 s_initialized = true; 47 return 0; 48} 49 50class ImageReader { 51public: 52 ImageReader(const char* data, size_t dataSize) 53 : m_data(data) 54 , m_size(dataSize) 55 , m_width(0) 56 , m_height(0) 57 { 58 libInit(); 59 } 60 61 void updateData(const char* data, size_t dataSize); 62 int setSize(size_t width, size_t height); 63 int sizeExtract(size_t& width, size_t& height); 64 int decode(size_t width, size_t height, ImageFrame*); 65 66private: 67 const char* m_data; 68 size_t m_size; 69 size_t m_width; 70 size_t m_height; 71}; 72 73// Function to get the original size of an image 74static int imgDecodeSetup(_Uintptrt data, img_t* img, unsigned flags) 75{ 76 ImageReader* reader = reinterpret_cast<ImageReader*>(data); 77 78 if ((img->flags & (IMG_W | IMG_H)) == (IMG_W | IMG_H)) 79 reader->setSize(img->w, img->h); 80 81 // Always: want to stop processing whether get a size or not. 82 return IMG_ERR_INTR; 83} 84 85void ImageReader::updateData(const char* data, size_t dataSize) 86{ 87 m_data = data; 88 m_size = dataSize; 89} 90 91int ImageReader::setSize(size_t width, size_t height) 92{ 93 m_width = width; 94 m_height = height; 95 return 0; 96} 97 98int ImageReader::sizeExtract(size_t& width, size_t& height) 99{ 100 img_decode_callouts_t callouts; 101 img_t img; 102 io_stream_t* iostream = io_open(IO_MEM, IO_READ, m_size, m_data); 103 if (!iostream) 104 return -1; 105 106 memset(&img, 0, sizeof(img)); 107 memset(&callouts, 0, sizeof(callouts)); 108 callouts.setup_f = imgDecodeSetup; 109 callouts.data = reinterpret_cast<_Uintptrt>(this); 110 111 int rc = img_load(s_ilib, iostream, &callouts, &img); 112 io_close(iostream); 113 if (rc != IMG_ERR_INTR) 114 return -1; 115 if (!m_width || !m_height) 116 return -1; 117 118 width = m_width; 119 height = m_height; 120 121 return 0; 122} 123 124int ImageReader::decode(size_t width, size_t height, ImageFrame* aFrame) 125{ 126 if (libInit() == -1) 127 return -1; 128 129 img_t img; 130 memset(&img, 0, sizeof(img)); 131 img.format = IMG_FMT_RGB888; 132 img.w = width; 133 img.h = height; 134 135 const int ColorComponents = 3; 136 // Use a multiple of 2 bytes to improve performance 137 int stride = (ColorComponents * width + 3) & ~3; 138 OwnArrayPtr<_uint8> buffer = adoptArrayPtr(new _uint8[stride * height]); 139 if (!buffer) 140 return -1; 141 img.access.direct.data = buffer.get(); 142 img.access.direct.stride = stride; 143 img.flags = IMG_W | IMG_H | IMG_DIRECT | IMG_FORMAT; 144 145 io_stream_t* iostream = io_open(IO_MEM, IO_READ, m_size, m_data); 146 if (!iostream) 147 return -1; 148 149 int rc = img_load_resize(s_ilib, iostream, 0, &img); 150 io_close(iostream); 151 if (rc != IMG_ERR_OK) 152 return -1; 153 154 for (unsigned j = 0; j < height; j++) { 155 _uint8* curPtr = buffer.get() + j * stride; 156 for (unsigned i = 0; i < width; i++) { 157 aFrame->setRGBA(i, j, curPtr[0], curPtr[1], curPtr[2], 255); 158 curPtr += 3; 159 } 160 } 161 return 0; 162} 163 164JPEGImageDecoder::JPEGImageDecoder(ImageSource::AlphaOption alphaOption, 165 ImageSource::GammaAndColorProfileOption gammaAndColorProfileOption) 166 : ImageDecoder(alphaOption, gammaAndColorProfileOption) 167{ 168} 169 170void JPEGImageDecoder::setData(SharedBuffer* data, bool allDataReceived) 171{ 172 ImageDecoder::setData(data, allDataReceived); 173 174 if (m_reader) 175 m_reader->updateData(m_data->data(), m_data->size()); 176} 177 178bool JPEGImageDecoder::isSizeAvailable() 179{ 180 if (!ImageDecoder::isSizeAvailable()) { 181 if (!m_reader) { 182 if (m_data) 183 m_reader = adoptPtr(new ImageReader(m_data->data(), m_data->size())); 184 if (!m_reader) 185 return false; 186 } 187 size_t width, height; 188 189 if (m_reader->sizeExtract(width, height) == -1) 190 return false; 191 if (!setSize(width, height)) 192 return false; 193 } 194 195 return ImageDecoder::isSizeAvailable(); 196} 197 198ImageFrame* JPEGImageDecoder::frameBufferAtIndex(size_t index) 199{ 200 if (!isAllDataReceived()) 201 return 0; 202 203 if (index) 204 return 0; 205 206 if (m_frameBufferCache.isEmpty()) 207 m_frameBufferCache.resize(1); 208 209 ImageFrame& frame = m_frameBufferCache[0]; 210 211 // Check to see if it's already decoded. 212 // FIXME: Could size change between calls to this method? 213 if (frame.status() == ImageFrame::FrameComplete) 214 return &frame; 215 216 if (frame.status() == ImageFrame::FrameEmpty) { 217 if (!size().width() || !size().height()) { 218 if (!isSizeAvailable()) 219 return 0; 220 } 221 if (!frame.setSize(size().width(), size().height())) { 222 setFailed(); 223 return 0; 224 } 225 frame.setStatus(ImageFrame::FramePartial); 226 // For JPEGs, the frame always fills the entire image. 227 frame.setOriginalFrameRect(IntRect(IntPoint(), size())); 228 } 229 230 if (!m_reader || m_reader->decode(size().width(), size().height(), &frame) == -1) { 231 setFailed(); 232 return 0; 233 } 234 235 frame.setStatus(ImageFrame::FrameComplete); 236 return &frame; 237} 238 239} // namespace WebCore 240 241