blob: 2a61935aba4e3ca6b2bc8229d896165a35e4176e [file] [log] [blame]
/*
* Copyright 2016 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Author: huibao@google.com (Huibao Lin)
#ifndef PAGESPEED_KERNEL_IMAGE_IMAGE_OPTIMIZER_H_
#define PAGESPEED_KERNEL_IMAGE_IMAGE_OPTIMIZER_H_
#include <memory>
#include "pagespeed/kernel/base/basictypes.h"
#include "pagespeed/kernel/base/message_handler.h"
#include "pagespeed/kernel/base/string.h"
#include "pagespeed/kernel/base/string_util.h"
#include "pagespeed/kernel/http/image_types.pb.h"
#include "pagespeed/kernel/image/image_optimizer.pb.h"
#include "pagespeed/kernel/image/image_util.h"
namespace net_instaweb {
class Timer;
}
namespace pagespeed {
namespace image_compression {
// Optimizes an image. The supported formats include GIF (both single-frame
// and animated), PNG, and JPEG. They can be converted to PNG, JPEG, or WebP
// (including lossy, lossless, or animated WebP). They can be resized to
// smaller dimensions. You specify the allowed options and the requested
// dimensions, and the method returns the format, dimensions, and contents
// for the actual output.
//
// If you specify a timer and the max_timeout_ms parameter, the method
// applies them to WebP images (other images are not affected by these
// parameters).
//
// This class can only be used to optimize one image, i.e., an ImageOptimizer
// object can only have the Optimize method called once.
class ImageOptimizer {
public:
explicit ImageOptimizer(net_instaweb::MessageHandler* message_handler) :
message_handler_(message_handler) {
}
// Applies all optimizations, for example, removing metadata, reducing chroma
// sampling, and reducing dimension, to the image.
//
// TODO(huibao): Instead of buffering the optimized image contents in a string
// let the Optimize method take a writer and stream the contents to the output
// directly.
bool Optimize(StringPiece original_contents,
GoogleString* optimized_contents,
ImageFormat* optimized_format);
void set_options(const pagespeed::image_compression::ImageOptions& options) {
options_ = options;
}
// Specifies the dimensions for resizing the image to. This parameter only
// applies to single-frame images. You can specify either width or height,
// or both. If you specify only one dimension, the image will be resized
// with the original aspect ratio. If the dimensions cannot be honored,
// the image can still be optimized in other ways. You can get the actual
// dimension of the optimized image by using the OutputDimension method.
void set_requested_dimension(
const pagespeed::image_compression::ImageDimensions&
requested_dimensions) {
requested_dim_ = requested_dimensions;
}
// Returns the actual dimensions of the optimized image, even when the image
// is not resized.
int optimized_width() { return optimized_width_; }
int optimized_height() { return optimized_height_; }
// Timer and was_timed_out only apply to WebP images.
void set_timer(net_instaweb::Timer* timer) { timer_ = timer; }
bool was_timed_out() const { return was_timed_out_; }
// Returns whether the image was encoded in lossy format, if the optimization
// succeeded.
bool UsesLossyFormat() const { return !desired_lossless_; }
private:
bool Run();
bool ComputeDesiredFormat();
bool ComputeResizedDimension();
bool ComputeDesiredQualityProgressive();
ImageFormat ImageTypeToImageFormat(net_instaweb::ImageType image_type);
bool ConfigureWriter();
bool RewriteSingleFrameImage();
bool RewriteAnimatedImage();
// External data.
net_instaweb::MessageHandler* const message_handler_;
pagespeed::image_compression::ImageOptions options_;
StringPiece original_contents_;
pagespeed::image_compression::ImageDimensions requested_dim_;
GoogleString* optimized_contents_ = nullptr;
net_instaweb::Timer* timer_ = nullptr;
std::unique_ptr<ConversionTimeoutHandler> timeout_handler_;
bool was_timed_out_ = false;
// Information about input image.
ImageFormat original_format_;
int original_width_ = -1;
int original_height_ = -1;
bool is_progressive_ = false;
bool is_animated_ = false;
bool is_transparent_ = false;
bool is_photo_ = false;
int original_quality_ = -1;
// Information about desired output.
ImageFormat optimized_format_;
int optimized_width_ = -1;
int optimized_height_ = -1;
int desired_quality_ = -1;
bool desired_progressive_ = false;
bool desired_lossless_ = false;
std::unique_ptr<ScanlineWriterConfig> writer_config_;
bool is_valid_ = true;
DISALLOW_COPY_AND_ASSIGN(ImageOptimizer);
};
} // namespace image_compression
} // namespace pagespeed
#endif // PAGESPEED_KERNEL_IMAGE_IMAGE_OPTIMIZER_H__