| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (c) 2010, Google Inc. All rights reserved. | 2 * Copyright (c) 2010, Google Inc. All rights reserved. |
| 3 * | 3 * |
| 4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
| 5 * modification, are permitted provided that the following conditions are | 5 * modification, are permitted provided that the following conditions are |
| 6 * met: | 6 * met: |
| 7 * | 7 * |
| 8 * * Redistributions of source code must retain the above copyright | 8 * * Redistributions of source code must retain the above copyright |
| 9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
| 10 * * Redistributions in binary form must reproduce the above | 10 * * Redistributions in binary form must reproduce the above |
| (...skipping 25 matching lines...) Expand all Loading... |
| 36 | 36 |
| 37 extern "C" { | 37 extern "C" { |
| 38 #include <setjmp.h> | 38 #include <setjmp.h> |
| 39 #include <stdio.h> // jpeglib.h needs stdio.h FILE | 39 #include <stdio.h> // jpeglib.h needs stdio.h FILE |
| 40 #include "jpeglib.h" | 40 #include "jpeglib.h" |
| 41 } | 41 } |
| 42 | 42 |
| 43 namespace blink { | 43 namespace blink { |
| 44 | 44 |
| 45 struct JPEGOutputBuffer : public jpeg_destination_mgr { | 45 struct JPEGOutputBuffer : public jpeg_destination_mgr { |
| 46 USING_FAST_MALLOC(JPEGOutputBuffer); | 46 DISALLOW_NEW(); |
| 47 WTF_MAKE_NONCOPYABLE(JPEGOutputBuffer); | |
| 48 public: | |
| 49 JPEGOutputBuffer() : jpeg_destination_mgr() {} | |
| 50 Vector<unsigned char>* output; | 47 Vector<unsigned char>* output; |
| 51 Vector<unsigned char> buffer; | 48 Vector<unsigned char> buffer; |
| 52 }; | 49 }; |
| 53 | 50 |
| 54 class JPEGImageEncoderStateImpl : public JPEGImageEncoderState { | 51 class JPEGImageEncoderStateImpl final : public JPEGImageEncoderState { |
| 55 public: | 52 public: |
| 56 JPEGImageEncoderStateImpl(jpeg_compress_struct* jpeg, JPEGOutputBuffer* dest
ination, jpeg_error_mgr* error) | 53 JPEGImageEncoderStateImpl() {} |
| 57 : m_jpeg(jpeg) | 54 ~JPEGImageEncoderStateImpl() override |
| 58 , m_destination(destination) | 55 { |
| 59 , m_error(error) {} | 56 jpeg_destroy_compress(&m_cinfo); |
| 60 ~JPEGImageEncoderStateImpl() override; | 57 m_cinfo.client_data = 0; |
| 61 jpeg_compress_struct* jpeg() { ASSERT(m_jpeg); return m_jpeg; } | 58 } |
| 62 JPEGOutputBuffer* outputBuffer() { return m_destination; } | 59 JPEGOutputBuffer* outputBuffer() { return &m_outputBuffer; } |
| 63 jpeg_error_mgr* error() { return m_error; } | 60 jpeg_compress_struct* cinfo() { return &m_cinfo; } |
| 61 jpeg_error_mgr* error() { return &m_error; } |
| 62 |
| 64 private: | 63 private: |
| 65 jpeg_compress_struct* m_jpeg; | 64 JPEGOutputBuffer m_outputBuffer; |
| 66 JPEGOutputBuffer* m_destination; | 65 jpeg_compress_struct m_cinfo; |
| 67 jpeg_error_mgr* m_error; | 66 jpeg_error_mgr m_error; |
| 68 }; | 67 }; |
| 69 | 68 |
| 70 static void prepareOutput(j_compress_ptr cinfo) | 69 static void prepareOutput(j_compress_ptr cinfo) |
| 71 { | 70 { |
| 72 JPEGOutputBuffer* out = static_cast<JPEGOutputBuffer*>(cinfo->dest); | 71 JPEGOutputBuffer* out = static_cast<JPEGOutputBuffer*>(cinfo->dest); |
| 73 const size_t internalBufferSize = 8192; | 72 const size_t internalBufferSize = 8192; |
| 74 out->buffer.resize(internalBufferSize); | 73 out->buffer.resize(internalBufferSize); |
| 75 out->next_output_byte = out->buffer.data(); | 74 out->next_output_byte = out->buffer.data(); |
| 76 out->free_in_buffer = out->buffer.size(); | 75 out->free_in_buffer = out->buffer.size(); |
| 77 } | 76 } |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 125 cinfo->comp_info[i].h_samp_factor = 1; | 124 cinfo->comp_info[i].h_samp_factor = 1; |
| 126 cinfo->comp_info[i].v_samp_factor = 1; | 125 cinfo->comp_info[i].v_samp_factor = 1; |
| 127 } | 126 } |
| 128 } | 127 } |
| 129 | 128 |
| 130 PassOwnPtr<JPEGImageEncoderState> JPEGImageEncoderState::create(const IntSize& i
mageSize, const double& quality, Vector<unsigned char>* output) | 129 PassOwnPtr<JPEGImageEncoderState> JPEGImageEncoderState::create(const IntSize& i
mageSize, const double& quality, Vector<unsigned char>* output) |
| 131 { | 130 { |
| 132 if (imageSize.width() <= 0 || imageSize.height() <= 0) | 131 if (imageSize.width() <= 0 || imageSize.height() <= 0) |
| 133 return nullptr; | 132 return nullptr; |
| 134 | 133 |
| 135 int compressionQuality = JPEGImageEncoder::computeCompressionQuality(quality
); | 134 OwnPtr<JPEGImageEncoderStateImpl> encoderState = adoptPtr(new JPEGImageEncod
erStateImpl()); |
| 136 JPEGOutputBuffer* destination = new JPEGOutputBuffer; | |
| 137 destination->output = output; | |
| 138 | 135 |
| 139 jpeg_compress_struct* cinfo = new jpeg_compress_struct; | 136 jpeg_compress_struct* cinfo = encoderState->cinfo(); |
| 140 jpeg_error_mgr* error = new jpeg_error_mgr; | 137 jpeg_error_mgr* error = encoderState->error(); |
| 141 | |
| 142 cinfo->err = jpeg_std_error(error); | 138 cinfo->err = jpeg_std_error(error); |
| 143 error->error_exit = handleError; | 139 error->error_exit = handleError; |
| 140 |
| 144 jmp_buf jumpBuffer; | 141 jmp_buf jumpBuffer; |
| 145 cinfo->client_data = &jumpBuffer; | 142 cinfo->client_data = &jumpBuffer; |
| 146 | 143 |
| 147 if (setjmp(jumpBuffer)) { | 144 if (setjmp(jumpBuffer)) { |
| 148 jpeg_destroy_compress(cinfo); | |
| 149 return nullptr; | 145 return nullptr; |
| 150 } | 146 } |
| 151 | 147 |
| 148 JPEGOutputBuffer* destination = encoderState->outputBuffer(); |
| 149 destination->output = output; |
| 150 |
| 152 jpeg_create_compress(cinfo); | 151 jpeg_create_compress(cinfo); |
| 153 cinfo->dest = destination; | 152 cinfo->dest = destination; |
| 154 cinfo->dest->init_destination = prepareOutput; | 153 cinfo->dest->init_destination = prepareOutput; |
| 155 cinfo->dest->empty_output_buffer = writeOutput; | 154 cinfo->dest->empty_output_buffer = writeOutput; |
| 156 cinfo->dest->term_destination = finishOutput; | 155 cinfo->dest->term_destination = finishOutput; |
| 157 | 156 |
| 158 | |
| 159 cinfo->image_height = imageSize.height(); | 157 cinfo->image_height = imageSize.height(); |
| 160 cinfo->image_width = imageSize.width(); | 158 cinfo->image_width = imageSize.width(); |
| 161 cinfo->in_color_space = JCS_RGB; | 159 cinfo->in_color_space = JCS_RGB; |
| 162 cinfo->input_components = 3; | 160 cinfo->input_components = 3; |
| 163 | 161 |
| 164 jpeg_set_defaults(cinfo); | 162 jpeg_set_defaults(cinfo); |
| 163 int compressionQuality = JPEGImageEncoder::computeCompressionQuality(quality
); |
| 165 jpeg_set_quality(cinfo, compressionQuality, TRUE); | 164 jpeg_set_quality(cinfo, compressionQuality, TRUE); |
| 166 disableSubsamplingForHighQuality(cinfo, compressionQuality); | 165 disableSubsamplingForHighQuality(cinfo, compressionQuality); |
| 167 jpeg_start_compress(cinfo, TRUE); | 166 jpeg_start_compress(cinfo, TRUE); |
| 168 | 167 |
| 169 return adoptPtr(new JPEGImageEncoderStateImpl(cinfo, destination, error)); | 168 cinfo->client_data = 0; |
| 170 } | 169 return encoderState.release(); |
| 171 | |
| 172 JPEGImageEncoderStateImpl::~JPEGImageEncoderStateImpl() | |
| 173 { | |
| 174 jpeg_destroy_compress(m_jpeg); | |
| 175 } | 170 } |
| 176 | 171 |
| 177 int JPEGImageEncoder::computeCompressionQuality(const double& quality) | 172 int JPEGImageEncoder::computeCompressionQuality(const double& quality) |
| 178 { | 173 { |
| 179 int compressionQuality = JPEGImageEncoder::DefaultCompressionQuality; | 174 int compressionQuality = JPEGImageEncoder::DefaultCompressionQuality; |
| 180 if (quality >= 0.0 && quality <= 1.0) | 175 if (quality >= 0.0 && quality <= 1.0) |
| 181 compressionQuality = static_cast<int>(quality * 100 + 0.5); | 176 compressionQuality = static_cast<int>(quality * 100 + 0.5); |
| 182 return compressionQuality; | 177 return compressionQuality; |
| 183 } | 178 } |
| 184 | 179 |
| 185 void JPEGImageEncoder::encodeWithPreInitializedState(JPEGImageEncoderState* enco
derState, const unsigned char* inputPixels) | 180 bool JPEGImageEncoder::encodeWithPreInitializedState(PassOwnPtr<JPEGImageEncoder
State> encoderState, const unsigned char* inputPixels) |
| 186 { | 181 { |
| 187 JPEGImageEncoderStateImpl* encoderStateImpl = static_cast<JPEGImageEncoderSt
ateImpl *>(encoderState); | 182 JPEGImageEncoderStateImpl* encoderStateImpl = static_cast<JPEGImageEncoderSt
ateImpl*>(encoderState.get()); |
| 188 | 183 |
| 189 Vector<JSAMPLE> row; | 184 Vector<JSAMPLE> row; |
| 185 row.resize(encoderStateImpl->cinfo()->image_width * encoderStateImpl->cinfo(
)->input_components); |
| 186 |
| 187 jmp_buf jumpBuffer; |
| 188 encoderStateImpl->cinfo()->client_data = &jumpBuffer; |
| 189 |
| 190 if (setjmp(jumpBuffer)) { |
| 191 return false; |
| 192 } |
| 193 |
| 190 unsigned char* pixels = const_cast<unsigned char*>(inputPixels); | 194 unsigned char* pixels = const_cast<unsigned char*>(inputPixels); |
| 191 | 195 const size_t pixelRowStride = encoderStateImpl->cinfo()->image_width * 4; |
| 192 row.resize(encoderStateImpl->jpeg()->image_width * encoderStateImpl->jpeg()-
>input_components); | 196 while (encoderStateImpl->cinfo()->next_scanline < encoderStateImpl->cinfo()-
>image_height) { |
| 193 | |
| 194 const size_t pixelRowStride = encoderStateImpl->jpeg()->image_width * 4; | |
| 195 while (encoderStateImpl->jpeg()->next_scanline < encoderStateImpl->jpeg()->i
mage_height) { | |
| 196 JSAMPLE* rowData = row.data(); | 197 JSAMPLE* rowData = row.data(); |
| 197 RGBAtoRGB(pixels, encoderStateImpl->jpeg()->image_width, rowData); | 198 RGBAtoRGB(pixels, encoderStateImpl->cinfo()->image_width, rowData); |
| 198 jpeg_write_scanlines(encoderStateImpl->jpeg(), &rowData, 1); | 199 jpeg_write_scanlines(encoderStateImpl->cinfo(), &rowData, 1); |
| 199 pixels += pixelRowStride; | 200 pixels += pixelRowStride; |
| 200 } | 201 } |
| 201 | 202 |
| 202 jpeg_finish_compress(encoderStateImpl->jpeg()); | 203 jpeg_finish_compress(encoderStateImpl->cinfo()); |
| 204 return true; |
| 203 } | 205 } |
| 204 | 206 |
| 205 bool JPEGImageEncoder::encode(const ImageDataBuffer& imageData, const double& qu
ality, Vector<unsigned char>* output) | 207 bool JPEGImageEncoder::encode(const ImageDataBuffer& imageData, const double& qu
ality, Vector<unsigned char>* output) |
| 206 { | 208 { |
| 207 if (!imageData.pixels()) | 209 if (!imageData.pixels()) |
| 208 return false; | 210 return false; |
| 209 IntSize imageSize(imageData.width(), imageData.height()); | |
| 210 const unsigned char* inputPixels = imageData.pixels(); | |
| 211 | 211 |
| 212 OwnPtr<JPEGImageEncoderState> encoderState = JPEGImageEncoderState::create(i
mageSize, quality, output); | 212 OwnPtr<JPEGImageEncoderState> encoderState = JPEGImageEncoderState::create(I
ntSize(imageData.width(), imageData.height()), quality, output); |
| 213 if (!encoderState.get()) | 213 if (!encoderState) |
| 214 return false; | 214 return false; |
| 215 | 215 |
| 216 JPEGImageEncoder::encodeWithPreInitializedState(encoderState.get(), inputPix
els); | 216 return JPEGImageEncoder::encodeWithPreInitializedState(encoderState.release(
), imageData.pixels()); |
| 217 return true; | |
| 218 } | 217 } |
| 219 | 218 |
| 220 } // namespace blink | 219 } // namespace blink |
| OLD | NEW |