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 | |
21 | namespace 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. |
30 | class 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 | |