2
* Copyright 2010 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: jmaessen@google.com (Jan Maessen)
19
#ifndef NET_INSTAWEB_REWRITER_PUBLIC_IMAGE_H_
20
#define NET_INSTAWEB_REWRITER_PUBLIC_IMAGE_H_
24
#include "net/instaweb/rewriter/image_types.pb.h"
25
#include "net/instaweb/rewriter/cached_result.pb.h"
26
#include "net/instaweb/rewriter/public/rewrite_options.h"
27
#include "net/instaweb/util/public/basictypes.h"
28
#include "net/instaweb/util/public/string.h"
29
#include "net/instaweb/util/public/string_util.h"
31
namespace net_instaweb {
40
// Images that are in the process of being transformed are represented by an
41
// Image. This class encapsulates various operations that are sensitive to
42
// the format of the compressed image file and of the image libraries we are
43
// using. In particular, the timing of compression and decompression
44
// operations may be a bit unexpected, because we may do these operations
45
// early in order to retrieve image metadata, or we may choose to skip them
46
// entirely if we don't need them or don't understand how to do them.
48
// In future we may need to plumb this to other data sources or change how
49
// metadata is retrieved; the object is to do so locally in this class without
50
// disrupting any of its clients.
58
struct ConversionBySourceVariable {
59
ConversionBySourceVariable()
60
: timeout_count(NULL),
64
Variable* timeout_count; // # of timed-out conversions.
65
Histogram* success_ms; // Successful conversion duration.
66
Histogram* failure_ms; // Failed (and non-timed-out) conversion duration.
69
struct ConversionVariables {
71
FROM_UNKNOWN_FORMAT = 0,
79
ConversionBySourceVariable* Get(VariableType var_type) {
80
if ((var_type < FROM_UNKNOWN_FORMAT) ||
81
(var_type >= NUM_VARIABLE_TYPE)) {
84
return &(vars[var_type]);
87
ConversionBySourceVariable vars[NUM_VARIABLE_TYPE];
90
struct CompressionOptions {
92
: preferred_webp(WEBP_NONE),
93
allow_webp_alpha(false),
94
webp_quality(RewriteOptions::kDefaultImageRecompressQuality),
95
jpeg_quality(RewriteOptions::kDefaultImageRecompressQuality),
96
progressive_jpeg_min_bytes(
97
RewriteOptions::kDefaultProgressiveJpegMinBytes),
98
progressive_jpeg(false),
99
convert_gif_to_png(false),
100
convert_png_to_jpeg(false),
101
convert_jpeg_to_webp(false),
102
recompress_jpeg(false),
103
recompress_png(false),
104
recompress_webp(false),
105
retain_color_profile(false),
106
retain_color_sampling(false),
107
retain_exif_data(false),
108
use_transparent_for_blank_image(false),
109
jpeg_num_progressive_scans(
110
RewriteOptions::kDefaultImageJpegNumProgressiveScans),
111
webp_conversion_timeout_ms(-1),
112
conversions_attempted(0),
113
preserve_lossless(false),
114
webp_conversion_variables(NULL) {}
116
// These options are set by the client to specify what type of
117
// conversion to perform:
118
PreferredWebp preferred_webp;
119
bool allow_webp_alpha;
122
int64 progressive_jpeg_min_bytes;
123
bool progressive_jpeg;
124
bool convert_gif_to_png;
125
bool convert_png_to_jpeg;
126
bool convert_jpeg_to_webp;
127
bool recompress_jpeg;
129
bool recompress_webp;
130
bool retain_color_profile;
131
bool retain_color_sampling;
132
bool retain_exif_data;
133
bool use_transparent_for_blank_image;
134
int64 jpeg_num_progressive_scans;
135
int64 webp_conversion_timeout_ms;
137
// These fields are set by the conversion routines to report
138
// characteristics of the conversion process.
139
int conversions_attempted;
140
bool preserve_lossless;
142
ConversionVariables* webp_conversion_variables;
147
// static method to convert image type to content type.
148
static const ContentType* TypeToContentType(ImageType t);
150
// Stores the image dimensions in natural_dim (on success, sets
151
// natural_dim->{width, height} and
152
// ImageUrlEncoder::HasValidDimensions(natural_dim) == true). This
153
// method can fail (ImageUrlEncoder::HasValidDimensions(natural_dim)
154
// == false) for various reasons: we don't understand the image
155
// format, we can't find the headers, the library doesn't support a
156
// particular encoding, etc. In that case the other fields are left
158
virtual void Dimensions(ImageDim* natural_dim) = 0;
160
// Returns the size of original input in bytes.
161
size_t input_size() const {
162
return original_contents_.size();
165
// Returns the size of output image in bytes.
166
size_t output_size() {
168
if (output_valid_ || ComputeOutputContents()) {
169
ret = output_contents_.size();
176
ImageType image_type() {
177
if (image_type_ == IMAGE_UNKNOWN) {
183
// If we had arbitrary license to convert to any webp format, what's the
184
// minimal webp library support that would be required for this image?
185
ResourceContext::LibWebpLevel MinimalWebpSupport() {
186
if (!rewrite_attempted_) {
187
ComputeOutputContents();
189
return minimal_webp_support_;
192
// Changes the size of the image to the given width and height. This will run
193
// image processing on the image, and return false if the image processing
194
// fails. Otherwise the image contents and type can change.
195
virtual bool ResizeTo(const ImageDim& new_dim) = 0;
197
// Enable the transformation to low res image. If low res image is enabled,
198
// all jpeg images are transformed to low quality jpeg images and all webp
199
// images to low quality webp images, if possible.
200
virtual void SetTransformToLowRes() = 0;
202
// Returns image-appropriate content type, or NULL if no content type is
203
// known. Result is a top-level const pointer and should not be deleted etc.
204
const ContentType* content_type() {
205
return TypeToContentType(image_type());
208
// Returns the best known image contents. If image type is not understood,
209
// then Contents() will have NULL data().
210
StringPiece Contents();
212
// Draws the given image on top of this one at the given offset. Returns true
214
virtual bool DrawImage(Image* image, int x, int y) = 0;
216
// Attempts to decode this image and load its raster into memory. If this
217
// returns false, future calls to DrawImage and ResizeTo will fail.
219
// If output_useful is true, the decoded version might be written out
220
// directly to user, so it may be worthwhile to make it efficient.
221
virtual bool EnsureLoaded(bool output_useful) = 0;
223
// Returns the image URL.
224
virtual const GoogleString& url() = 0;
226
// Returns the debug message.
227
virtual const GoogleString& debug_message() = 0;
229
// Returns the resized image debug message.
230
virtual const GoogleString& resize_debug_message() = 0;
233
explicit Image(const StringPiece& original_contents);
234
explicit Image(ImageType type);
237
virtual void ComputeImageType() = 0;
238
virtual bool ComputeOutputContents() = 0;
240
// Inject desired resized dimensions directly for testing.
241
virtual void SetResizedDimensions(const ImageDim& dim) = 0;
243
// Determines whether it's a good idea to convert this image to progressive
245
virtual bool ShouldConvertToProgressive(int64 quality) const = 0;
248
ImageType image_type_; // Lazily initialized, initially IMAGE_UNKNOWN.
249
const StringPiece original_contents_;
250
GoogleString output_contents_; // Lazily filled.
251
bool output_valid_; // Indicates output_contents_ now correct.
252
bool rewrite_attempted_; // Indicates if we tried rewriting for this.
253
ResourceContext::LibWebpLevel minimal_webp_support_;
256
friend class ImageTestingPeer;
257
friend class ImageTest;
259
DISALLOW_COPY_AND_ASSIGN(Image);
262
// Image owns none of its inputs. All of the arguments to NewImage(...) (the
263
// original_contents in particular) must outlive the Image object itself. The
264
// intent is that an Image is created in a scoped fashion from an existing known
267
// The options should be set via Image::SetOptions after construction, before
268
// the image is used for anything but determining its natural dimension size.
270
// TODO(jmarantz): It would seem natural to fold the ImageOptions into the
271
// Image object itself.
272
Image* NewImage(const StringPiece& original_contents,
273
const GoogleString& url,
274
const StringPiece& file_prefix,
275
Image::CompressionOptions* options,
277
MessageHandler* handler);
279
// Creates a blank image of the given dimensions and type.
280
// For now, this is assumed to be an 8-bit 4-channel image transparent image.
281
Image* BlankImageWithOptions(int width, int height, ImageType type,
282
const StringPiece& tmp_dir,
284
MessageHandler* handler,
285
Image::CompressionOptions* options);
287
} // namespace net_instaweb
289
#endif // NET_INSTAWEB_REWRITER_PUBLIC_IMAGE_H_