1// Copyright 2013 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef FLUTTER_LIB_UI_PAINTING_IMAGE_DESCRIPTOR_H_
6#define FLUTTER_LIB_UI_PAINTING_IMAGE_DESCRIPTOR_H_
7
8#include <cstdint>
9#include <memory>
10#include <optional>
11
12#include "flutter/fml/macros.h"
13#include "flutter/lib/ui/dart_wrapper.h"
14#include "flutter/lib/ui/painting/immutable_buffer.h"
15#include "third_party/skia/include/codec/SkCodec.h"
16#include "third_party/skia/include/core/SkImageGenerator.h"
17#include "third_party/skia/include/core/SkImageInfo.h"
18#include "third_party/skia/src/codec/SkCodecImageGenerator.h"
19#include "third_party/tonic/dart_library_natives.h"
20
21namespace flutter {
22
23/// Creates an image descriptor for encoded or decoded image data, describing
24/// the width, height, and bytes per pixel for that image.
25///
26/// This class will hold a reference on the underlying image data, and in the
27/// case of compressed data, an SkCodec and SkImageGenerator for the data.
28/// The Codec initialization actually happens in initEncoded, making
29/// initstantiateCodec a lightweight operation.
30class ImageDescriptor : public RefCountedDartWrappable<ImageDescriptor> {
31 public:
32 ~ImageDescriptor() override = default;
33
34 // This must be kept in sync with the enum in painting.dart
35 enum PixelFormat {
36 kRGBA8888,
37 kBGRA8888,
38 };
39
40 /// Asynchronously initlializes an ImageDescriptor for an encoded image, as
41 /// long as the format is supported by Skia.
42 ///
43 /// Calling this method will result in creating an SkCodec and
44 /// SkImageGenerator to read EXIF corrected dimensions from the image data.
45 static void initEncoded(Dart_NativeArguments args);
46
47 /// Synchronously initializes an ImageDescriptor for decompressed image data
48 /// as specified by the PixelFormat.
49 static void initRaw(Dart_Handle descriptor_handle,
50 fml::RefPtr<ImmutableBuffer> data,
51 int width,
52 int height,
53 int row_bytes,
54 PixelFormat pixel_format);
55
56 /// Associates a flutter::Codec object with the dart.ui Codec handle.
57 void instantiateCodec(Dart_Handle codec, int target_width, int target_height);
58
59 /// The width of this image, EXIF oriented if applicable.
60 int width() const { return image_info_.width(); }
61
62 /// The height of this image. EXIF oriented if applicable.
63 int height() const { return image_info_.height(); }
64
65 /// The bytes per pixel of the image.
66 int bytesPerPixel() const { return image_info_.bytesPerPixel(); }
67
68 /// The byte length of the first row of the image.
69 ///
70 /// Defaults to width() * 4.
71 int row_bytes() const {
72 return row_bytes_.value_or(
73 static_cast<size_t>(image_info_.width() * image_info_.bytesPerPixel()));
74 }
75
76 /// Whether the given target_width or target_height differ from width() and
77 /// height() respectively.
78 bool should_resize(int target_width, int target_height) const {
79 return target_width != width() || target_height != height();
80 }
81
82 /// The underlying buffer for this image.
83 sk_sp<SkData> data() const { return buffer_; }
84
85 sk_sp<SkImage> image() const;
86
87 /// Whether this descriptor represents compressed (encoded) data or not.
88 bool is_compressed() const { return generator_ || platform_image_generator_; }
89
90 /// The orientation corrected image info for this image.
91 const SkImageInfo& image_info() const { return image_info_; }
92
93 /// Gets the scaled dimensions of this image, if backed by a codec that can
94 /// perform efficient subpixel scaling.
95 SkISize get_scaled_dimensions(float scale) {
96 if (generator_) {
97 return generator_->getScaledDimensions(scale);
98 }
99 return image_info_.dimensions();
100 }
101
102 /// Gets pixels for this image transformed based on the EXIF orientation tag,
103 /// if applicable.
104 bool get_pixels(const SkPixmap& pixmap) const;
105
106 void dispose() {
107 ClearDartWrapper();
108 generator_.reset();
109 platform_image_generator_.reset();
110 }
111
112 size_t GetAllocationSize() const override {
113 return sizeof(ImageDescriptor) + sizeof(SkImageInfo) + buffer_->size();
114 }
115
116 static void RegisterNatives(tonic::DartLibraryNatives* natives);
117
118 private:
119 ImageDescriptor(sk_sp<SkData> buffer,
120 const SkImageInfo& image_info,
121 std::optional<size_t> row_bytes);
122 ImageDescriptor(sk_sp<SkData> buffer, std::unique_ptr<SkCodec> codec);
123 ImageDescriptor(sk_sp<SkData> buffer,
124 std::unique_ptr<SkImageGenerator> generator);
125
126 sk_sp<SkData> buffer_;
127 std::shared_ptr<SkCodecImageGenerator> generator_;
128 std::unique_ptr<SkImageGenerator> platform_image_generator_;
129 const SkImageInfo image_info_;
130 std::optional<size_t> row_bytes_;
131
132 const SkImageInfo CreateImageInfo() const;
133
134 DEFINE_WRAPPERTYPEINFO();
135 FML_FRIEND_MAKE_REF_COUNTED(ImageDescriptor);
136 FML_DISALLOW_COPY_AND_ASSIGN(ImageDescriptor);
137
138 friend class ImageDecoderFixtureTest;
139};
140
141} // namespace flutter
142
143#endif // FLUTTER_LIB_UI_PAINTING_IMAGE_DESCRIPTOR_H_
144