blob: 227c161fc687c842a714ae5d0e1bb168734a49ff [file] [log] [blame]
/*
* Copyright 2013 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 Lin
#ifndef PAGESPEED_KERNEL_IMAGE_PIXEL_FORMAT_OPTIMIZER_H_
#define PAGESPEED_KERNEL_IMAGE_PIXEL_FORMAT_OPTIMIZER_H_
#include <cstddef>
#include "pagespeed/kernel/base/basictypes.h"
#include "pagespeed/kernel/base/message_handler.h"
#include "pagespeed/kernel/base/scoped_ptr.h"
#include "pagespeed/kernel/image/image_util.h"
#include "pagespeed/kernel/image/scanline_interface.h"
#include "pagespeed/kernel/image/scanline_status.h"
namespace pagespeed {
namespace image_compression {
// PixelFormatOptimizer removes an unused channel from the image. This
// corresponds to changing the pixel format to a more compact one.
// Currently it only removes opaque alpha channel and changes RGBA_8888
// to RGB_888.
//
// To determine if a channel is unused, PixelFormatOptimizer has to examine
// every pixel in the image. Thus, the entire image may be buffered before
// the first output scanline can be retrieved. However, as soon as
// PixelFormatOptimizer finds a pixel with all channels used, it will stop
// buffering and become ready to serve the first scanline.
//
// TODO(huibao): Check how often gray scale images are encoded as color. If it
// happens often, implement the conversion of RGBA_8888/RGB_888 to GRAY_8.
class PixelFormatOptimizer : public ScanlineReaderInterface {
public:
explicit PixelFormatOptimizer(net_instaweb::MessageHandler* handler);
virtual ~PixelFormatOptimizer();
// PixelFormatOptimizer acquires ownership of reader, even in case of failure.
ScanlineStatus Initialize(ScanlineReaderInterface* reader);
virtual ScanlineStatus ReadNextScanlineWithStatus(void** out_scanline_bytes);
// Resets the resizer to its initial state. Always returns true.
virtual bool Reset();
// Returns number of bytes required to store a scanline.
virtual size_t GetBytesPerScanline() {
return bytes_per_row_;
}
// Returns true if there are more scanlines to read. Returns false if the
// object has not been initialized or all of the scanlines have been read.
virtual bool HasMoreScanLines() {
return (output_row_ < GetImageHeight());
}
// Returns the height of the image.
virtual size_t GetImageHeight() {
return reader_->GetImageHeight();
}
// Returns the width of the image.
virtual size_t GetImageWidth() {
return reader_->GetImageWidth();
}
// Returns the pixel format of the image.
virtual PixelFormat GetPixelFormat() {
return pixel_format_;
}
// Returns true if the image is encoded in progressive / interlacing format.
virtual bool IsProgressive() {
return reader_->IsProgressive();
}
// This method should not be called. If it does get called, in DEBUG mode it
// will throw a FATAL error and in RELEASE mode it does nothing.
virtual ScanlineStatus InitializeWithStatus(const void* image_buffer,
size_t buffer_length);
private:
net_instaweb::scoped_ptr<ScanlineReaderInterface> reader_;
size_t bytes_per_row_;
PixelFormat pixel_format_;
size_t output_row_;
bool strip_alpha_;
bool was_initialized_;
// Buffer for storing decoded scanlines.
net_instaweb::scoped_array<uint8_t> input_lines_;
// Number of rows which have been examined and buffered.
size_t input_row_;
// Buffer for storing a single converted scanline.
net_instaweb::scoped_array<uint8_t> output_line_;
net_instaweb::MessageHandler* message_handler_;
DISALLOW_COPY_AND_ASSIGN(PixelFormatOptimizer);
};
} // namespace image_compression
} // namespace pagespeed
#endif // PAGESPEED_KERNEL_IMAGE_PIXEL_FORMAT_OPTIMIZER_H_