blob: 5ee9190f3a03f64b95ff47797430ab22a5697af5 [file] [log] [blame]
/**
* Copyright 2010 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: jmaessen@google.com (Jan Maessen)
#ifndef NET_INSTAWEB_REWRITER_PUBLIC_IMAGE_H_
#define NET_INSTAWEB_REWRITER_PUBLIC_IMAGE_H_
#include "base/basictypes.h"
#include "net/instaweb/rewriter/public/image_dim.h"
#include <string>
#include "net/instaweb/util/public/string_util.h"
#ifdef USE_SYSTEM_OPENCV
#include "cv.h"
#else
#include "third_party/opencv/src/opencv/include/opencv/cv.h"
#endif
namespace net_instaweb {
struct ContentType;
struct ImageDim;
class FileSystem;
class MessageHandler;
class Writer;
// The following four helper functions were moved here for testability. We ran
// into problems with sign extension under different compiler versions, and we'd
// like to catch regressions on that front in the future.
// char to int *without sign extension*.
inline int CharToInt(char c) {
uint8 uc = static_cast<uint8>(c);
return static_cast<int>(uc);
}
inline int JpegIntAtPosition(const StringPiece& buf, size_t pos) {
return (CharToInt(buf[pos]) << 8) |
(CharToInt(buf[pos + 1]));
}
inline int GifIntAtPosition(const StringPiece& buf, size_t pos) {
return (CharToInt(buf[pos + 1]) << 8) |
(CharToInt(buf[pos]));
}
inline int PngIntAtPosition(const StringPiece& buf, size_t pos) {
return (CharToInt(buf[pos ]) << 24) |
(CharToInt(buf[pos + 1]) << 16) |
(CharToInt(buf[pos + 2]) << 8) |
(CharToInt(buf[pos + 3]));
}
namespace ImageHeaders {
// Constants that are shared by Image and its tests.
extern const char kPngHeader[];
extern const size_t kPngHeaderLength;
extern const char kPngIHDR[];
extern const size_t kPngIHDRLength;
extern const size_t kIHDRDataStart;
extern const size_t kPngIntSize;
extern const char kGifHeader[];
extern const size_t kGifHeaderLength;
extern const size_t kGifDimStart;
extern const size_t kGifIntSize;
extern const size_t kJpegIntSize;
} // namespace ImageHeaders
class Image {
public:
// Images that are in the process of being transformed are represented by an
// Image. This class encapsulates various operations that are sensitive to
// the format of the compressed image file and of the image libraries we are
// using. In particular, the timing of compression and decompression
// operations may be a bit unexpected, because we may do these operations
// early in order to retrieve image metadata, or we may choose to skip them
// entirely if we don't need them or don't understand how to do them.
//
// In future we may need to plumb this to other data sources or change how
// metadata is retrieved; the object is to do so locally in this class without
// disrupting any of its clients.
enum Type {
IMAGE_UNKNOWN = 0,
IMAGE_JPEG,
IMAGE_PNG,
IMAGE_GIF,
};
// Image owns none of its inputs. All of the arguments to Image(...) (the
// original_contents in particular) must outlive the Image object itself. The
// intent is that an Image is created in a scoped fashion from an existing
// known resource.
Image(const StringPiece& original_contents,
const std::string& url,
const StringPiece& file_prefix,
FileSystem* file_system,
MessageHandler* handler);
~Image();
// Stores the image dimensions in natural_dim (on success, sets
// natural_dim->{width, height} and natural_dim->valid = true). This method
// can fail (natural_dim->valid == false) for various reasons: we don't
// understand the image format (eg a gif), we can't find the headers, the
// library doesn't support a particular encoding, etc. In that case the other
// fields are left alone.
void Dimensions(ImageDim* natural_dim);
// Returns the size of original input in bytes.
size_t input_size() const {
return original_contents_.size();
}
// Returns the size of output image in bytes.
size_t output_size() {
size_t ret;
if (output_valid_ || ComputeOutputContents()) {
ret = output_contents_.size();
} else {
ret = input_size();
}
return ret;
}
Type image_type() {
if (image_type_ == IMAGE_UNKNOWN) {
ComputeImageType();
}
return image_type_;
}
// Changes the size of the image to the given width and height. This will run
// image processing on the image, and return false if the image processing
// fails. Otherwise the image contents and type can change.
bool ResizeTo(const ImageDim& new_dim);
// UndoResize lets us bail out if a resize actually cost space!
void UndoResize();
// Returns image-appropriate content type, or NULL if no content type is
// known. Result is a top-level const pointer and should not be deleted etc.
const ContentType* content_type();
// Returns the best known image contents. If image type is not understood,
// then Contents() will have NULL data().
StringPiece Contents();
private:
// Internal methods used only in image.cc (see there for more).
void ComputeImageType();
void FindJpegSize();
inline void FindPngSize();
inline void FindGifSize();
bool LoadOpenCV();
void CleanOpenCV();
bool ComputeOutputContents();
const std::string file_prefix_;
FileSystem* file_system_;
MessageHandler* handler_;
Type image_type_; // Lazily initialized, initially IMAGE_UNKNOWN.
const StringPiece original_contents_;
std::string output_contents_; // Lazily filled.
bool output_valid_; // Indicates output_contents_ now correct.
std::string opencv_filename_; // Lazily holds generated name of temp file.
IplImage* opencv_image_; // Lazily filled on OpenCV load.
bool opencv_load_possible_; // Attempt opencv_load in future?
bool resized_;
const std::string& url_;
ImageDim dims_;
DISALLOW_COPY_AND_ASSIGN(Image);
};
} // namespace net_instaweb
#endif // NET_INSTAWEB_REWRITER_PUBLIC_IMAGE_H_