Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(17)

Unified Diff: ios/web/public/image_fetcher/webp_decoder.mm

Issue 2699633006: Move WebpDecoder from ios/web to components/image_fetcher (Closed)
Patch Set: Separate header Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « ios/web/public/image_fetcher/webp_decoder.h ('k') | ios/web/public/image_fetcher/webp_decoder_unittest.mm » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: ios/web/public/image_fetcher/webp_decoder.mm
diff --git a/ios/web/public/image_fetcher/webp_decoder.mm b/ios/web/public/image_fetcher/webp_decoder.mm
deleted file mode 100644
index d5e7d923add86c93ae77a8ed9a6417e2673f0639..0000000000000000000000000000000000000000
--- a/ios/web/public/image_fetcher/webp_decoder.mm
+++ /dev/null
@@ -1,309 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "ios/web/public/image_fetcher/webp_decoder.h"
-
-#import <Foundation/Foundation.h>
-#include <stdint.h>
-#import <UIKit/UIKit.h>
-
-#include "base/logging.h"
-#include "base/metrics/histogram_macros.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-namespace {
-
-class WebpDecoderDelegate : public webp_transcode::WebpDecoder::Delegate {
- public:
- WebpDecoderDelegate() = default;
-
- NSData* data() const { return decoded_image_; }
-
- // WebpDecoder::Delegate methods
- void OnFinishedDecoding(bool success) override {
- if (!success)
- decoded_image_ = nil;
- }
-
- void SetImageFeatures(
- size_t total_size,
- webp_transcode::WebpDecoder::DecodedImageFormat format) override {
- decoded_image_ = [[NSMutableData alloc] initWithCapacity:total_size];
- }
-
- void OnDataDecoded(NSData* data) override {
- DCHECK(decoded_image_);
- [decoded_image_ appendData:data];
- }
-
- private:
- ~WebpDecoderDelegate() override {}
- NSMutableData* decoded_image_;
-
- DISALLOW_COPY_AND_ASSIGN(WebpDecoderDelegate);
-};
-
-// Content-type header for WebP images.
-const char kWEBPFirstMagicPattern[] = "RIFF";
-const char kWEBPSecondMagicPattern[] = "WEBP";
-
-const uint8_t kNumIfdEntries = 15;
-const unsigned int kExtraDataSize = 16;
-// 10b for signature/header + n * 12b entries + 4b for IFD terminator:
-const unsigned int kExtraDataOffset = 10 + 12 * kNumIfdEntries + 4;
-const unsigned int kHeaderSize = kExtraDataOffset + kExtraDataSize;
-const int kRecompressionThreshold = 64 * 64; // Threshold in pixels.
-const CGFloat kJpegQuality = 0.85;
-
-// Adapted from libwebp example dwebp.c.
-void PutLE16(uint8_t* const dst, uint32_t value) {
- dst[0] = (value >> 0) & 0xff;
- dst[1] = (value >> 8) & 0xff;
-}
-
-void PutLE32(uint8_t* const dst, uint32_t value) {
- PutLE16(dst + 0, (value >> 0) & 0xffff);
- PutLE16(dst + 2, (value >> 16) & 0xffff);
-}
-
-void WriteTiffHeader(uint8_t* dst,
- int width,
- int height,
- int bytes_per_px,
- bool has_alpha) {
- // For non-alpha case, we omit tag 0x152 (ExtraSamples).
- const uint8_t num_ifd_entries =
- has_alpha ? kNumIfdEntries : kNumIfdEntries - 1;
- uint8_t tiff_header[kHeaderSize] = {
- 0x49, 0x49, 0x2a, 0x00, // little endian signature
- 8, 0, 0, 0, // offset to the unique IFD that follows
- // IFD (offset = 8). Entries must be written in increasing tag order.
- num_ifd_entries, 0, // Number of entries in the IFD (12 bytes each).
- 0x00, 0x01, 3, 0, 1, 0, 0, 0, 0, 0, 0, 0, // 10: Width (TBD)
- 0x01, 0x01, 3, 0, 1, 0, 0, 0, 0, 0, 0, 0, // 22: Height (TBD)
- 0x02, 0x01, 3, 0, bytes_per_px, 0, 0, 0, // 34: BitsPerSample: 8888
- kExtraDataOffset + 0, 0, 0, 0, 0x03, 0x01, 3, 0, 1, 0, 0, 0, 1, 0, 0,
- 0, // 46: Compression: none
- 0x06, 0x01, 3, 0, 1, 0, 0, 0, 2, 0, 0, 0, // 58: Photometric: RGB
- 0x11, 0x01, 4, 0, 1, 0, 0, 0, // 70: Strips offset:
- kHeaderSize, 0, 0, 0, // data follows header
- 0x12, 0x01, 3, 0, 1, 0, 0, 0, 1, 0, 0, 0, // 82: Orientation: topleft
- 0x15, 0x01, 3, 0, 1, 0, 0, 0, // 94: SamplesPerPixels
- bytes_per_px, 0, 0, 0, 0x16, 0x01, 3, 0, 1, 0, 0, 0, 0, 0, 0,
- 0, // 106: Rows per strip (TBD)
- 0x17, 0x01, 4, 0, 1, 0, 0, 0, 0, 0, 0, 0, // 118: StripByteCount (TBD)
- 0x1a, 0x01, 5, 0, 1, 0, 0, 0, // 130: X-resolution
- kExtraDataOffset + 8, 0, 0, 0, 0x1b, 0x01, 5, 0, 1, 0, 0,
- 0, // 142: Y-resolution
- kExtraDataOffset + 8, 0, 0, 0, 0x1c, 0x01, 3, 0, 1, 0, 0, 0, 1, 0, 0,
- 0, // 154: PlanarConfiguration
- 0x28, 0x01, 3, 0, 1, 0, 0, 0, 2, 0, 0, 0, // 166: ResolutionUnit (inch)
- 0x52, 0x01, 3, 0, 1, 0, 0, 0, 1, 0, 0, 0, // 178: ExtraSamples: rgbA
- 0, 0, 0, 0, // 190: IFD terminator
- // kExtraDataOffset:
- 8, 0, 8, 0, 8, 0, 8, 0, // BitsPerSample
- 72, 0, 0, 0, 1, 0, 0, 0 // 72 pixels/inch, for X/Y-resolution
- };
-
- // Fill placeholders in IFD:
- PutLE32(tiff_header + 10 + 8, width);
- PutLE32(tiff_header + 22 + 8, height);
- PutLE32(tiff_header + 106 + 8, height);
- PutLE32(tiff_header + 118 + 8, width * bytes_per_px * height);
- if (!has_alpha)
- PutLE32(tiff_header + 178, 0);
-
- memcpy(dst, tiff_header, kHeaderSize);
-}
-
-} // namespace
-
-namespace webp_transcode {
-
-// static
-NSData* WebpDecoder::DecodeWebpImage(NSData* webp_image) {
- scoped_refptr<WebpDecoderDelegate> delegate(new WebpDecoderDelegate);
-
- scoped_refptr<webp_transcode::WebpDecoder> decoder(
- new webp_transcode::WebpDecoder(delegate.get()));
-
- decoder->OnDataReceived(webp_image);
- DLOG_IF(ERROR, !delegate->data()) << "WebP image decoding failed.";
- return delegate->data();
-}
-
-// static
-bool WebpDecoder::IsWebpImage(const std::string& image_data) {
- if (image_data.length() < 12)
- return false;
- return image_data.compare(0, 4, kWEBPFirstMagicPattern) == 0 &&
- image_data.compare(8, 4, kWEBPSecondMagicPattern) == 0;
-}
-
-// static
-size_t WebpDecoder::GetHeaderSize() {
- return kHeaderSize;
-}
-
-WebpDecoder::WebpDecoder(WebpDecoder::Delegate* delegate)
- : delegate_(delegate), state_(READING_FEATURES), has_alpha_(0) {
- DCHECK(delegate_.get());
- const bool rv = WebPInitDecoderConfig(&config_);
- DCHECK(rv);
-}
-
-WebpDecoder::~WebpDecoder() {
- WebPFreeDecBuffer(&config_.output);
-}
-
-void WebpDecoder::OnDataReceived(NSData* data) {
- DCHECK(data);
- switch (state_) {
- case READING_FEATURES:
- DoReadFeatures(data);
- break;
- case READING_DATA:
- DoReadData(data);
- break;
- case DONE:
- DLOG(WARNING) << "Received WebP data but decoding is finished. Ignoring.";
- break;
- }
-}
-
-void WebpDecoder::Stop() {
- if (state_ != DONE) {
- state_ = DONE;
- DLOG(WARNING) << "Unexpected end of WebP data.";
- delegate_->OnFinishedDecoding(false);
- }
-}
-
-void WebpDecoder::DoReadFeatures(NSData* data) {
- DCHECK_EQ(READING_FEATURES, state_);
- DCHECK(data);
- if (features_)
- [features_ appendData:data];
- else
- features_.reset([[NSMutableData alloc] initWithData:data]);
- VP8StatusCode status =
- WebPGetFeatures(static_cast<const uint8_t*>([features_ bytes]),
- [features_ length], &config_.input);
- switch (status) {
- case VP8_STATUS_OK: {
- has_alpha_ = config_.input.has_alpha;
- const uint32_t width = config_.input.width;
- const uint32_t height = config_.input.height;
- const size_t bytes_per_px = has_alpha_ ? 4 : 3;
- const int stride = bytes_per_px * width;
- const size_t image_data_size = stride * height;
- const size_t total_size = image_data_size + kHeaderSize;
- // Force pre-multiplied alpha.
- config_.output.colorspace = has_alpha_ ? MODE_rgbA : MODE_RGB;
- config_.output.u.RGBA.stride = stride;
- // Create the output buffer.
- config_.output.u.RGBA.size = image_data_size;
- uint8_t* dst = static_cast<uint8_t*>(malloc(total_size));
- if (!dst) {
- DLOG(ERROR) << "Could not allocate WebP decoding buffer (size = "
- << total_size << ").";
- delegate_->OnFinishedDecoding(false);
- state_ = DONE;
- break;
- }
- WriteTiffHeader(dst, width, height, bytes_per_px, has_alpha_);
- output_buffer_.reset([[NSData alloc] initWithBytesNoCopy:dst
- length:total_size
- freeWhenDone:YES]);
- config_.output.is_external_memory = 1;
- config_.output.u.RGBA.rgba = dst + kHeaderSize;
- // Start decoding.
- state_ = READING_DATA;
- incremental_decoder_.reset(WebPINewDecoder(&config_.output));
- DoReadData(features_);
- features_.reset();
- break;
- }
- case VP8_STATUS_NOT_ENOUGH_DATA:
- // Do nothing.
- break;
- default:
- DLOG(ERROR) << "Error in WebP image features.";
- delegate_->OnFinishedDecoding(false);
- state_ = DONE;
- break;
- }
-}
-
-void WebpDecoder::DoReadData(NSData* data) {
- DCHECK_EQ(READING_DATA, state_);
- DCHECK(incremental_decoder_);
- DCHECK(data);
- VP8StatusCode status =
- WebPIAppend(incremental_decoder_.get(),
- static_cast<const uint8_t*>([data bytes]), [data length]);
- switch (status) {
- case VP8_STATUS_SUSPENDED:
- // Do nothing: re-compression to JPEG or PNG cannot be done incrementally.
- // Wait for the whole image to be decoded.
- break;
- case VP8_STATUS_OK: {
- bool rv = DoSendData();
- DLOG_IF(ERROR, !rv) << "Error in WebP image conversion.";
- state_ = DONE;
- delegate_->OnFinishedDecoding(rv);
- break;
- }
- default:
- DLOG(ERROR) << "Error in WebP image decoding.";
- delegate_->OnFinishedDecoding(false);
- state_ = DONE;
- break;
- }
-}
-
-bool WebpDecoder::DoSendData() {
- DCHECK_EQ(READING_DATA, state_);
- int width, height;
- uint8_t* data_ptr = WebPIDecGetRGB(incremental_decoder_.get(), nullptr,
- &width, &height, nullptr);
- if (!data_ptr)
- return false;
- DCHECK_EQ(static_cast<const uint8_t*>([output_buffer_ bytes]) + kHeaderSize,
- data_ptr);
- base::scoped_nsobject<NSData> result_data;
- // When the WebP image is larger than |kRecompressionThreshold| it is
- // compressed to JPEG or PNG. Otherwise, the uncompressed TIFF is used.
- DecodedImageFormat format = TIFF;
- if (width * height > kRecompressionThreshold) {
- base::scoped_nsobject<UIImage> tiff_image(
- [[UIImage alloc] initWithData:output_buffer_]);
- if (!tiff_image)
- return false;
- // Compress to PNG if the image is transparent, JPEG otherwise.
- // TODO(droger): Use PNG instead of JPEG if the WebP image is lossless.
- if (has_alpha_) {
- result_data.reset(UIImagePNGRepresentation(tiff_image));
- format = PNG;
- } else {
- result_data.reset(UIImageJPEGRepresentation(tiff_image, kJpegQuality));
- format = JPEG;
- }
- if (!result_data)
- return false;
- } else {
- result_data.reset(output_buffer_);
- }
- UMA_HISTOGRAM_ENUMERATION("WebP.DecodedImageFormat", format,
- DECODED_FORMAT_COUNT);
- delegate_->SetImageFeatures([result_data length], format);
- delegate_->OnDataDecoded(result_data);
- output_buffer_.reset();
- return true;
-}
-
-} // namespace webp_transcode
« no previous file with comments | « ios/web/public/image_fetcher/webp_decoder.h ('k') | ios/web/public/image_fetcher/webp_decoder_unittest.mm » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698