Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(76)

Side by Side Diff: third_party/WebKit/Source/platform/image-encoders/skia/JPEGImageEncoder.cpp

Issue 1807553002: Fix JPEGImageEncoder memory leak (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@2661
Patch Set: Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « third_party/WebKit/Source/platform/image-encoders/skia/JPEGImageEncoder.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
OLDNEW
« no previous file with comments | « third_party/WebKit/Source/platform/image-encoders/skia/JPEGImageEncoder.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698