2
* Copyright 2009 Google Inc.
4
* Licensed under the Apache License, Version 2.0 (the "License");
5
* you may not use this file except in compliance with the License.
6
* You may obtain a copy of the License at
8
* http://www.apache.org/licenses/LICENSE-2.0
10
* Unless required by applicable law or agreed to in writing, software
11
* distributed under the License is distributed on an "AS IS" BASIS,
12
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
* See the License for the specific language governing permissions and
14
* limitations under the License.
17
// Author: Victor Chudnovsky
19
#ifndef PAGESPEED_KERNEL_IMAGE_WEBP_OPTIMIZER_H_
20
#define PAGESPEED_KERNEL_IMAGE_WEBP_OPTIMIZER_H_
22
// For libwebp, encode.h must be included before gif2webp_util.h.
24
#include "third_party/libwebp/src/webp/encode.h"
25
#include "third_party/libwebp/examples/gif2webp_util.h"
26
#include "pagespeed/kernel/base/basictypes.h"
27
#include "pagespeed/kernel/base/scoped_ptr.h"
28
#include "pagespeed/kernel/base/string.h"
29
#include "pagespeed/kernel/image/image_frame_interface.h"
30
#include "pagespeed/kernel/image/image_util.h"
31
#include "pagespeed/kernel/image/scanline_interface.h"
32
#include "pagespeed/kernel/image/scanline_status.h"
34
namespace net_instaweb {
40
namespace image_compression {
42
using net_instaweb::MessageHandler;
44
struct WebpConfiguration {
45
// This contains a subset of the options in WebPConfig and
48
typedef bool (*WebpProgressHook)(int percent, void* user_data);
51
: lossless(true), quality(75), method(3), target_size(0),
52
alpha_compression(1), alpha_filtering(1), alpha_quality(100),
53
progress_hook(NULL), user_data(NULL) {}
54
void CopyTo(WebPConfig* webp_config) const;
56
int lossless; // Lossless encoding (0=lossy(default), 1=lossless).
57
float quality; // between 0 (smallest file) and 100 (biggest)
58
int method; // quality/speed trade-off (0=fast, 6=slower-better)
60
// Parameters related to lossy compression only:
61
int target_size; // if non-zero, set the desired target size in bytes.
62
// Takes precedence over the 'compression' parameter.
63
int alpha_compression; // Algorithm for encoding the alpha plane (0 = none,
64
// 1 = compressed with WebP lossless). Default is 1.
65
int alpha_filtering; // Predictive filtering method for alpha plane.
66
// 0: none, 1: fast, 2: best. Default is 1.
67
int alpha_quality; // Between 0 (smallest size) and 100 (lossless).
70
WebpProgressHook progress_hook; // If non-NULL, called during encoding.
72
void* user_data; // Can be used by progress_hook. This
73
// pointer remains owned by the client and
74
// must remain valid until
75
// WebpScanlineWriter::FinalizeWrite()
78
// NOTE: If you add more fields to this struct that feed into
79
// WebPConfig, please update the CopyTo() method.
82
class WebpFrameWriter : public MultipleFrameWriter {
84
explicit WebpFrameWriter(MessageHandler* handler);
85
virtual ~WebpFrameWriter();
87
// Sets the WebP configuration to be 'config', which should be a
88
// WebpConfiguration* and should not be NULL.
89
virtual ScanlineStatus Initialize(const void* config, GoogleString* out);
91
// image_spec must remain valid for the lifetime of
93
virtual ScanlineStatus PrepareImage(const ImageSpec* image_spec);
95
// frame_spec must remain valid while the frame is being written.
96
virtual ScanlineStatus PrepareNextFrame(const FrameSpec* frame_spec);
98
virtual ScanlineStatus WriteNextScanline(const void *scanline_bytes);
100
// Note that even after WriteNextScanline() has been called,
101
// Initialize() and FinalizeWrite() may be called repeatedly to
102
// write the image with, say, different configs.
103
virtual ScanlineStatus FinalizeWrite();
106
// The function to be called by libwebp's progress hook (with 'this'
107
// as the user data), which in turn will call the user-supplied function
108
// in progress_hook_, passing it progress_hook_data_.
109
static int ProgressHook(int percent, const WebPPicture* picture);
111
// Commits the just-read frame to the animation cache.
112
ScanlineStatus CacheCurrentFrame();
114
// Utility function to deallocate libwebp-defined data structures.
115
void FreeWebpStructs();
117
// This class does NOT own image_spec_.
118
const ImageSpec* image_spec_;
119
FrameSpec frame_spec_;
121
// Zero-based index of the next frame (after the current one) to be
125
// Zero-based index of the next scanline to be written.
126
size_px next_scanline_;
128
// Flag to indicate whether the current frame is empty, due to at
129
// least one of its dimensions being zero. Note that all frames must
130
// fit completely within their image (see the comment in
131
// image_frame_interface.h), so out-of-bounds frames are not
135
// Number of pixels to advance by exactly one row.
136
size_px frame_stride_px_;
138
// Pointer to the next pixel to be written via WriteNextScanline().
139
uint32_t* frame_position_px_;
141
// The number of bytes per pixel in the current frame.
142
uint32_t frame_bytes_per_pixel_;
144
// libwebp objects for the WebP generation.
145
WebPPicture* webp_image_;
146
WebPPicture webp_frame_;
147
WebPFrameCache* webp_frame_cache_;
149
WebPConfig webp_config_;
155
// Pointer to the webp output.
156
GoogleString* output_image_;
158
// Whether the image has an alpha channel.
161
// Whether PrepareImage() has been called successfully.
162
bool image_prepared_;
164
// The user-supplied progress hook.
165
WebpConfiguration::WebpProgressHook progress_hook_;
167
// The user-supplied user data for progress_hook. This pointer must
168
// remain valid until FinalizeWrite() completes. This class does NOT
169
// take ownership of this pointer.
170
void* progress_hook_data_;
172
// WebP does not have native support for gray scale images. The workaround
173
// is to replicate the luminance to RGB; then WebP can compress the expanded
174
// images efficiently.
175
bool should_expand_gray_to_rgb_;
177
DISALLOW_COPY_AND_ASSIGN(WebpFrameWriter);
180
// WebpScanlineReader decodes WebP images. It returns a scanline (a row of
181
// pixels) each time it is called. The output format is RGB_888 if the input
182
// image does not have alpha channel, or RGBA_8888 otherwise. Animated WebP
184
class WebpScanlineReader : public ScanlineReaderInterface {
186
explicit WebpScanlineReader(MessageHandler* handler);
187
virtual ~WebpScanlineReader();
189
// Reset the scanline reader to its initial state.
190
virtual bool Reset();
192
// Initialize the reader with the given image stream. Note that image_buffer
193
// must remain unchanged until the *first* call to ReadNextScanline().
194
virtual ScanlineStatus InitializeWithStatus(const void* image_buffer,
195
size_t buffer_length);
197
// Return the next row of pixels. The entire image is decoded the first
198
// time ReadNextScanline() is called, but only one scanline is returned
200
virtual ScanlineStatus ReadNextScanlineWithStatus(void** out_scanline_bytes);
202
// Return the number of bytes in a row (without padding).
203
virtual size_t GetBytesPerScanline() { return bytes_per_row_; }
205
virtual bool HasMoreScanLines() { return (row_ < height_); }
206
virtual PixelFormat GetPixelFormat() { return pixel_format_; }
207
virtual size_t GetImageHeight() { return height_; }
208
virtual size_t GetImageWidth() { return width_; }
209
// WebP does not have progressive mode.
210
virtual bool IsProgressive() { return false; }
213
// Buffer and length of the input (compressed) image.
214
const uint8_t* image_buffer_;
217
PixelFormat pixel_format_;
220
size_t bytes_per_row_;
222
bool was_initialized_;
224
// Buffer for holding the decoded pixels.
225
net_instaweb::scoped_array<uint8_t> pixels_;
227
MessageHandler* message_handler_;
229
DISALLOW_COPY_AND_ASSIGN(WebpScanlineReader);
232
} // namespace image_compression
234
} // namespace pagespeed
236
#endif // PAGESPEED_KERNEL_IMAGE_WEBP_OPTIMIZER_H_