skia_safe/core/
image.rs

1use crate::{
2    gpu, prelude::*, AlphaType, Bitmap, ColorSpace, ColorType, Data, EncodedImageFormat, IPoint,
3    IRect, ISize, ImageFilter, ImageGenerator, ImageInfo, Matrix, Paint, Picture, Pixmap,
4    SamplingOptions, Shader, SurfaceProps, TextureCompressionType, TileMode,
5};
6use skia_bindings::{self as sb, SkImage, SkRefCntBase};
7use std::{fmt, ptr};
8
9pub use super::CubicResampler;
10
11#[deprecated(since = "0.62.0", note = "Use TextureCompressionType")]
12pub use crate::TextureCompressionType as CompressionType;
13
14#[deprecated(since = "0.63.0", note = "Use images::BitDepth")]
15pub use images::BitDepth;
16
17pub mod images {
18    use std::{mem, ptr};
19
20    use skia_bindings as sb;
21
22    #[allow(unused)] // doc only
23    use crate::ColorType;
24    use crate::{
25        prelude::*, AlphaType, Bitmap, ColorSpace, Data, IPoint, IRect, ISize, Image, ImageFilter,
26        ImageGenerator, ImageInfo, Matrix, Paint, Picture, SurfaceProps, TextureCompressionType,
27    };
28
29    /// Creates a CPU-backed [`Image`] from `bitmap`, sharing or copying `bitmap` pixels. If the bitmap
30    /// is marked immutable, and its pixel memory is shareable, it may be shared
31    /// instead of copied.
32    ///
33    /// [`Image`] is returned if bitmap is valid. Valid [`Bitmap`] parameters include:
34    /// dimensions are greater than zero;
35    /// each dimension fits in 29 bits;
36    /// [`ColorType`] and [`AlphaType`] are valid, and [`ColorType`] is not [`ColorType::Unknown`];
37    /// row bytes are large enough to hold one row of pixels;
38    /// pixel address is not `None`.
39    ///
40    /// * `bitmap` - [`ImageInfo`], row bytes, and pixels
41    ///
42    /// Returns: created [`Image`], or `None`
43    pub fn raster_from_bitmap(bitmap: &Bitmap) -> Option<Image> {
44        Image::from_ptr(unsafe { sb::C_SkImages_RasterFromBitmap(bitmap.native()) })
45    }
46
47    /// Creates a CPU-backed [`Image`] from compressed data.
48    ///
49    /// This method will decompress the compressed data and create an image wrapping
50    /// it. Any mipmap levels present in the compressed data are discarded.
51    ///
52    /// * `data` - compressed data to store in [`Image`]
53    /// * `dimension` - width and height of full [`Image`]
54    /// * `ty` - type of compression used
55    ///
56    /// Returns: created [`Image`], or `None`
57    pub fn raster_from_compressed_texture_data(
58        data: impl Into<Data>,
59        dimensions: impl Into<ISize>,
60        ty: TextureCompressionType,
61    ) -> Option<Image> {
62        let dimensions = dimensions.into();
63        Image::from_ptr(unsafe {
64            sb::C_SkImages_RasterFromCompressedTextureData(
65                data.into().into_ptr(),
66                dimensions.width,
67                dimensions.height,
68                ty,
69            )
70        })
71    }
72
73    /// Return a [`Image`] using the encoded data, but attempts to defer decoding until the
74    /// image is actually used/drawn. This deferral allows the system to cache the result, either on the
75    /// CPU or on the GPU, depending on where the image is drawn. If memory is low, the cache may
76    /// be purged, causing the next draw of the image to have to re-decode.
77    ///
78    /// If `alpha_type` is `None`, the image's alpha type will be chosen automatically based on the
79    /// image format. Transparent images will default to [`AlphaType::Premul`]. If `alpha_type` contains
80    /// [`AlphaType::Premul`] or [`AlphaType::Unpremul`], that alpha type will be used. Forcing opaque
81    /// (passing [`AlphaType::Opaque`]) is not allowed, and will return `None`.
82    ///
83    /// If the encoded format is not supported, `None` is returned.
84    ///
85    /// * `encoded` - the encoded data
86    ///
87    /// Returns: created [`Image`], or `None`
88    ///
89    /// example: <https://fiddle.skia.org/c/@Image_DeferredFromEncodedData>
90    pub fn deferred_from_encoded_data(
91        data: impl Into<Data>,
92        alpha_type: impl Into<Option<AlphaType>>,
93    ) -> Option<Image> {
94        Image::from_ptr(unsafe {
95            sb::C_SkImages_DeferredFromEncodedData(
96                data.into().into_ptr(),
97                alpha_type
98                    .into()
99                    .map(|at| &at as *const _)
100                    .unwrap_or(ptr::null()),
101            )
102        })
103    }
104
105    /// Creates [`Image`] from data returned by `image_generator`. The image data will not be created
106    /// (on either the CPU or GPU) until the image is actually drawn.
107    /// Generated data is owned by [`Image`] and may not be shared or accessed.
108    ///
109    /// [`Image`] is returned if generator data is valid. Valid data parameters vary by type of data
110    /// and platform.
111    ///
112    /// `image_generator` may wrap [`Picture`] data, codec data, or custom data.
113    ///
114    /// * `image_generator` - stock or custom routines to retrieve [`Image`]
115    ///
116    /// Returns: created [`Image`], or `None`
117    pub fn deferred_from_generator(mut image_generator: ImageGenerator) -> Option<Image> {
118        let image = Image::from_ptr(unsafe {
119            sb::C_SkImages_DeferredFromGenerator(image_generator.native_mut())
120        });
121        mem::forget(image_generator);
122        image
123    }
124
125    pub use skia_bindings::SkImages_BitDepth as BitDepth;
126    variant_name!(BitDepth::F16);
127
128    /// Creates [`Image`] from picture. Returned [`Image`] width and height are set by dimensions.
129    /// [`Image`] draws picture with matrix and paint, set to `bit_depth` and `color_space`.
130    ///
131    /// The Picture data is not turned into an image (CPU or GPU) until it is drawn.
132    ///
133    /// If matrix is `None`, draws with identity [`Matrix`]. If paint is `None`, draws
134    /// with default [`Paint`]. `color_space` may be `None`.
135    ///
136    /// * `picture` - stream of drawing commands
137    /// * `dimensions` - width and height
138    /// * `matrix` - [`Matrix`] to rotate, scale, translate, and so on; may be `None`
139    /// * `paint` - [`Paint`] to apply transparency, filtering, and so on; may be `None`
140    /// * `bit_depth` - 8-bit integer or 16-bit float: per component
141    /// * `color_space` - range of colors; may be `None`
142    /// * `props` - props to use when rasterizing the picture
143    ///
144    /// Returns: created [`Image`], or `None`
145    pub fn deferred_from_picture(
146        picture: impl Into<Picture>,
147        dimensions: impl Into<ISize>,
148        matrix: Option<&Matrix>,
149        paint: Option<&Paint>,
150        bit_depth: BitDepth,
151        color_space: impl Into<Option<ColorSpace>>,
152        props: impl Into<Option<SurfaceProps>>,
153    ) -> Option<Image> {
154        Image::from_ptr(unsafe {
155            sb::C_SkImages_DeferredFromPicture(
156                picture.into().into_ptr(),
157                dimensions.into().native(),
158                matrix.native_ptr_or_null(),
159                paint.native_ptr_or_null(),
160                bit_depth,
161                color_space.into().into_ptr_or_null(),
162                props.into().unwrap_or_default().native(),
163            )
164        })
165    }
166
167    // TODO: RasterFromPixmapCopy
168    // TODO: RasterFromPixmap
169
170    /// Creates CPU-backed [`Image`] from pixel data described by info.
171    /// The pixels data will *not* be copied.
172    ///
173    /// [`Image`] is returned if [`ImageInfo`] is valid. Valid [`ImageInfo`] parameters include:
174    /// dimensions are greater than zero;
175    /// each dimension fits in 29 bits;
176    /// [`ColorType`] and [`AlphaType`] are valid, and [`ColorType`] is not [`ColorType::Unknown`];
177    /// `row_bytes` are large enough to hold one row of pixels;
178    /// pixels is not `None`, and contains enough data for [`Image`].
179    ///
180    /// * `info` - contains width, height, [`AlphaType`], [`ColorType`], [`ColorSpace`]
181    /// * `pixels` - address or pixel storage
182    /// * `row_bytes` - size of pixel row or larger
183    ///
184    /// Returns: [`Image`] sharing pixels, or `None`
185    pub fn raster_from_data(
186        info: &ImageInfo,
187        pixels: impl Into<Data>,
188        row_bytes: usize,
189    ) -> Option<Image> {
190        Image::from_ptr(unsafe {
191            sb::C_SkImages_RasterFromData(info.native(), pixels.into().into_ptr(), row_bytes)
192        })
193    }
194
195    /// Creates a filtered [`Image`] on the CPU. filter processes the src image, potentially
196    /// changing the color, position, and size. subset is the bounds of src that are processed by
197    /// filter. `clip_bounds` is the expected bounds of the filtered [`Image`]. `out_subset` is
198    /// required storage for the actual bounds of the filtered [`Image`]. `offset` is required
199    /// storage for translation of returned [`Image`].
200    ///
201    /// Returns `None` a filtered result could not be created.
202    ///
203    /// Useful for animation of [`ImageFilter`] that varies size from frame to frame. `out_subset`
204    /// describes the valid bounds of returned image. offset translates the returned [`Image`] to
205    /// keep subsequent animation frames aligned with respect to each other.
206    ///
207    /// * `src` - the image to be filtered
208    /// * `filter` - the image filter to be applied
209    /// * `subset` - bounds of [`Image`] processed by filter
210    /// * `clip_bounds` - expected bounds of filtered [`Image`]
211    ///
212    /// Returns filtered SkImage, or `None`:
213    /// * `out_subset` - storage for returned [`Image`] bounds
214    /// * `offset` - storage for returned [`Image`] translation Returns: filtered [`Image`], or
215    ///   `None`
216    pub fn make_with_filter(
217        image: impl Into<Image>,
218        image_filter: &ImageFilter,
219        subset: impl AsRef<IRect>,
220        clip_bounds: impl AsRef<IRect>,
221    ) -> Option<(Image, IRect, IPoint)> {
222        let mut out_subset = IRect::default();
223        let mut offset = IPoint::default();
224
225        unsafe {
226            Image::from_ptr(sb::C_SkImages_MakeWithFilter(
227                image.into().into_ptr(),
228                image_filter.native(),
229                subset.as_ref().native(),
230                clip_bounds.as_ref().native(),
231                out_subset.native_mut(),
232                offset.native_mut(),
233            ))
234        }
235        .map(|i| (i, out_subset, offset));
236        None
237    }
238}
239
240/// CachingHint selects whether Skia may internally cache [`Bitmap`] generated by
241/// decoding [`Image`], or by copying [`Image`] from GPU to CPU. The default behavior
242/// allows caching [`Bitmap`].
243///
244/// Choose [`CachingHint::Disallow`] if [`Image`] pixels are to be used only once, or
245/// if [`Image`] pixels reside in a cache outside of Skia, or to reduce memory pressure.
246///
247/// Choosing [`CachingHint::Allow`] does not ensure that pixels will be cached.
248/// [`Image`] pixels may not be cached if memory requirements are too large or
249/// pixels are not accessible.
250pub use skia_bindings::SkImage_CachingHint as CachingHint;
251variant_name!(CachingHint::Allow);
252
253/// [`Image`] describes a two dimensional array of pixels to draw. The pixels may be
254/// decoded in a raster bitmap, encoded in a [`Picture`] or compressed data stream,
255/// or located in GPU memory as a GPU texture.
256///
257/// [`Image`] cannot be modified after it is created. [`Image`] may allocate additional
258/// storage as needed; for instance, an encoded [`Image`] may decode when drawn.
259///
260/// [`Image`] width and height are greater than zero. Creating an [`Image`] with zero width
261/// or height returns [`Image`] equal to nullptr.
262///
263/// [`Image`] may be created from [`Bitmap`], [`Pixmap`], [`crate::Surface`], [`Picture`], encoded streams,
264/// GPU texture, YUV_ColorSpace data, or hardware buffer. Encoded streams supported
265/// include BMP, GIF, HEIF, ICO, JPEG, PNG, WBMP, WebP. Supported encoding details
266/// vary with platform.
267pub type Image = RCHandle<SkImage>;
268unsafe_send_sync!(Image);
269require_base_type!(SkImage, sb::SkRefCnt);
270
271impl NativeBase<SkRefCntBase> for SkImage {}
272
273impl NativeRefCountedBase for SkImage {
274    type Base = SkRefCntBase;
275}
276
277impl fmt::Debug for Image {
278    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
279        let mut d = f.debug_struct("Image");
280        let d = d
281            .field("image_info", &self.image_info())
282            .field("unique_id", &self.unique_id())
283            .field("alpha_type", &self.alpha_type())
284            .field("color_type", &self.color_type())
285            .field("color_space", &self.color_space())
286            .field("is_texture_backed", &self.is_texture_backed());
287        #[cfg(feature = "gpu")]
288        let d = d.field("texture_size", &self.texture_size());
289        d.field("has_mipmaps", &self.has_mipmaps())
290            .field("is_lazy_generated", &self.is_lazy_generated())
291            .finish()
292    }
293}
294
295impl Image {
296    /// Creates [`Image`] from [`ImageInfo`], sharing pixels.
297    ///
298    /// [`Image`] is returned if [`ImageInfo`] is valid. Valid [`ImageInfo`] parameters include:
299    /// dimensions are greater than zero;
300    /// each dimension fits in 29 bits;
301    /// [`ColorType`] and [`AlphaType`] are valid, and [`ColorType`] is not [`ColorType::Unknown`];
302    /// rowBytes are large enough to hold one row of pixels;
303    /// pixels is not nullptr, and contains enough data for [`Image`].
304    ///
305    /// - `info`       contains width, height, [`AlphaType`], [`ColorType`], [`ColorSpace`]
306    /// - `pixels`     address or pixel storage
307    /// - `rowBytes`   size of pixel row or larger
308    ///
309    /// Returns: [`Image`] sharing pixels, or `None`
310    #[deprecated(since = "0.63.0", note = "use images::raster_from_data()")]
311    pub fn from_raster_data(
312        info: &ImageInfo,
313        pixels: impl Into<Data>,
314        row_bytes: usize,
315    ) -> Option<Image> {
316        images::raster_from_data(info, pixels, row_bytes)
317    }
318
319    /// Creates [`Image`] from bitmap, sharing or copying bitmap pixels. If the bitmap
320    /// is marked immutable, and its pixel memory is shareable, it may be shared
321    /// instead of copied.
322    ///
323    /// [`Image`] is returned if bitmap is valid. Valid [`Bitmap`] parameters include:
324    /// dimensions are greater than zero;
325    /// each dimension fits in 29 bits;
326    /// [`ColorType`] and [`AlphaType`] are valid, and [`ColorType`] is not [`ColorType::Unknown`];
327    /// row bytes are large enough to hold one row of pixels;
328    /// pixel address is not `null`.
329    ///
330    /// - `bitmap`   [`ImageInfo`], row bytes, and pixels
331    ///
332    /// Returns: created [`Image`], or `None`
333    ///
334    /// example: <https://fiddle.skia.org/c/@Image_MakeFromBitmap>
335    #[deprecated(since = "0.63.0", note = "use images::raster_from_bitmap()")]
336    pub fn from_bitmap(bitmap: &Bitmap) -> Option<Image> {
337        images::raster_from_bitmap(bitmap)
338    }
339
340    /// Creates [`Image`] from data returned by `image_generator`. Generated data is owned by [`Image`] and
341    /// may not be shared or accessed.
342    ///
343    /// [`Image`] is returned if generator data is valid. Valid data parameters vary by type of data
344    /// and platform.
345    ///
346    /// imageGenerator may wrap [`Picture`] data, codec data, or custom data.
347    ///
348    /// - `image_generator`   stock or custom routines to retrieve [`Image`]
349    ///
350    /// Returns: created [`Image`], or `None`
351    #[deprecated(since = "0.63.0", note = "use images::deferred_from_generator()")]
352    pub fn from_generator(image_generator: ImageGenerator) -> Option<Image> {
353        images::deferred_from_generator(image_generator)
354    }
355
356    /// See [`Self::from_encoded_with_alpha_type()`]
357    pub fn from_encoded(data: impl Into<Data>) -> Option<Image> {
358        images::deferred_from_encoded_data(data, None)
359    }
360
361    /// Return an image backed by the encoded data, but attempt to defer decoding until the image
362    /// is actually used/drawn. This deferral allows the system to cache the result, either on the
363    /// CPU or on the GPU, depending on where the image is drawn. If memory is low, the cache may
364    /// be purged, causing the next draw of the image to have to re-decode.
365    ///
366    /// If alphaType is `None`, the image's alpha type will be chosen automatically based on the
367    /// image format. Transparent images will default to [`AlphaType::Premul`]. If alphaType contains
368    /// [`AlphaType::Premul`] or [`AlphaType::Unpremul`], that alpha type will be used. Forcing opaque
369    /// (passing [`AlphaType::Opaque`]) is not allowed, and will return nullptr.
370    ///
371    /// This is similar to `decode_to_{raster,texture}`, but this method will attempt to defer the
372    /// actual decode, while the `decode_to`... method explicitly decode and allocate the backend
373    /// when the call is made.
374    ///
375    /// If the encoded format is not supported, `None` is returned.
376    ///
377    /// - `encoded`   the encoded data
378    ///
379    /// Returns: created [`Image`], or `None`
380    ///
381    /// example: <https://fiddle.skia.org/c/@Image_MakeFromEncoded>
382    pub fn from_encoded_with_alpha_type(
383        data: impl Into<Data>,
384        alpha_type: impl Into<Option<AlphaType>>,
385    ) -> Option<Image> {
386        images::deferred_from_encoded_data(data, alpha_type)
387    }
388
389    #[deprecated(since = "0.35.0", note = "Removed without replacement")]
390    pub fn decode_to_raster(_encoded: &[u8], _subset: impl Into<Option<IRect>>) -> ! {
391        panic!("Removed without replacement")
392    }
393
394    /// Creates a CPU-backed [`Image`] from compressed data.
395    ///
396    /// This method will decompress the compressed data and create an image wrapping
397    /// it. Any mipmap levels present in the compressed data are discarded.
398    ///
399    /// - `data`      compressed data to store in [`Image`]
400    /// - `width`     width of full [`Image`]
401    /// - `height`    height of full [`Image`]
402    /// - `ty`        type of compression used
403    ///
404    /// Returns: created [`Image`], or `None`
405    #[deprecated(
406        since = "0.63.0",
407        note = "use images::raster_from_compressed_texture_data()"
408    )]
409    pub fn new_raster_from_compressed(
410        data: impl Into<Data>,
411        dimensions: impl Into<ISize>,
412        ty: TextureCompressionType,
413    ) -> Option<Image> {
414        images::raster_from_compressed_texture_data(data, dimensions, ty)
415    }
416
417    /// See [`Self::from_picture_with_props()`]
418    #[deprecated(since = "0.63.0", note = "use images::deferred_from_picture()")]
419    pub fn from_picture(
420        picture: impl Into<Picture>,
421        dimensions: impl Into<ISize>,
422        matrix: Option<&Matrix>,
423        paint: Option<&Paint>,
424        bit_depth: BitDepth,
425        color_space: impl Into<Option<ColorSpace>>,
426    ) -> Option<Image> {
427        images::deferred_from_picture(
428            picture,
429            dimensions,
430            matrix,
431            paint,
432            bit_depth,
433            color_space,
434            None,
435        )
436    }
437
438    /// Creates [`Image`] from picture. Returned [`Image`] width and height are set by dimensions.
439    /// [`Image`] draws picture with matrix and paint, set to bitDepth and colorSpace.
440    ///
441    /// If matrix is `None`, draws with identity [`Matrix`]. If paint is `None`, draws
442    /// with default [`Paint`]. color_space may be `None`.
443    ///
444    /// - `picture`      stream of drawing commands
445    /// - `dimensions`   width and height
446    /// - `matrix`       [`Matrix`] to rotate, scale, translate, and so on; may be `None`
447    /// - `paint`        [`Paint`] to apply transparency, filtering, and so on; may be `None`
448    /// - `bitDepth`     8-bit integer or 16-bit float: per component
449    /// - `color_space`  range of colors; may be `None`
450    /// - `props`        props to use when rasterizing the picture
451    ///
452    /// Returns: created [`Image`], or `None`
453    #[deprecated(since = "0.63.0", note = "use images::deferred_from_picture()")]
454    pub fn from_picture_with_props(
455        picture: impl Into<Picture>,
456        dimensions: impl Into<ISize>,
457        matrix: Option<&Matrix>,
458        paint: Option<&Paint>,
459        bit_depth: BitDepth,
460        color_space: impl Into<Option<ColorSpace>>,
461        props: SurfaceProps,
462    ) -> Option<Image> {
463        images::deferred_from_picture(
464            picture,
465            dimensions,
466            matrix,
467            paint,
468            bit_depth,
469            color_space,
470            Some(props),
471        )
472    }
473
474    /// Creates a GPU-backed [`Image`] from compressed data.
475    ///
476    /// This method will return an [`Image`] representing the compressed data.
477    /// If the GPU doesn't support the specified compression method, the data
478    /// will be decompressed and then wrapped in a GPU-backed image.
479    ///
480    /// Note: one can query the supported compression formats via
481    /// [`gpu::RecordingContext::compressed_backend_format`].
482    ///
483    /// - `context`      GPU context
484    /// - `data`         compressed data to store in [`Image`]
485    /// - `width`        width of full [`Image`]
486    /// - `height`       height of full [`Image`]
487    /// - `ty`           type of compression used
488    /// - `mipmapped`    does 'data' contain data for all the mipmap levels?
489    /// - `is_protected`  do the contents of 'data' require DRM protection (on Vulkan)?
490    ///
491    /// Returns: created [`Image`], or `None`
492    #[cfg(feature = "gpu")]
493    #[deprecated(
494        since = "0.63.0",
495        note = "use gpu::images::texture_from_compressed_texture_data()"
496    )]
497    pub fn new_texture_from_compressed(
498        context: &mut gpu::DirectContext,
499        data: Data,
500        dimensions: impl Into<ISize>,
501        ty: TextureCompressionType,
502        mipmapped: impl Into<Option<gpu::Mipmapped>>,
503        is_protected: impl Into<Option<gpu::Protected>>,
504    ) -> Option<Image> {
505        gpu::images::texture_from_compressed_texture_data(
506            context,
507            data,
508            dimensions,
509            ty,
510            mipmapped,
511            is_protected,
512        )
513    }
514
515    #[cfg(feature = "gpu")]
516    #[deprecated(since = "0.35.0", note = "Removed without replacement")]
517    pub fn from_compressed(
518        _context: &mut gpu::RecordingContext,
519        _data: Data,
520        _dimensions: impl Into<ISize>,
521        _ct: TextureCompressionType,
522    ) -> ! {
523        panic!("Removed without replacement.")
524    }
525
526    /// Creates [`Image`] from GPU texture associated with context. GPU texture must stay
527    /// valid and unchanged until `texture_release_proc` is called. `texture_release_proc` is
528    /// passed `release_context` when [`Image`] is deleted or no longer refers to texture.
529    ///
530    /// [`Image`] is returned if format of `backend_texture` is recognized and supported.
531    /// Recognized formats vary by GPU back-end.
532    ///
533    /// Note: When using a DDL recording context, `texture_release_proc` will be called on the
534    /// GPU thread after the DDL is played back on the direct context.
535    ///
536    /// * `context`               GPU context
537    /// * `backend_texture`       Texture residing on GPU
538    /// * `origin`                Origin of `backend_texture`
539    /// * `color_type`            Color type of the resulting image
540    /// * `alpha_type`            Alpha type of the resulting image
541    /// * `color_space`           This describes the color space of this image's contents, as
542    ///                           seen after sampling. In general, if the format of the backend
543    ///                           texture is SRGB, some linear `color_space` should be supplied
544    ///                           (e.g., [`ColorSpace::new_srgb_linear()`])). If the format of the
545    ///                           backend texture is linear, then the `color_space` should include
546    ///                           a description of the transfer function as
547    ///                           well (e.g., [`ColorSpace::MakeSRGB`]()).
548    /// * `texture_release_proc`  Function called when texture can be released
549    /// * `release_context`       State passed to `texture_release_proc`
550    ///
551    /// Returns: Created [`Image`], or `None`
552    #[cfg(feature = "gpu")]
553    pub fn from_texture(
554        context: &mut gpu::RecordingContext,
555        backend_texture: &gpu::BackendTexture,
556        origin: gpu::SurfaceOrigin,
557        color_type: ColorType,
558        alpha_type: AlphaType,
559        color_space: impl Into<Option<ColorSpace>>,
560    ) -> Option<Image> {
561        gpu::images::borrow_texture_from(
562            context,
563            backend_texture,
564            origin,
565            color_type,
566            alpha_type,
567            color_space,
568        )
569    }
570
571    #[deprecated(since = "0.27.0", note = "renamed, use new_cross_context_from_pixmap")]
572    #[cfg(feature = "gpu")]
573    pub fn from_pixmap_cross_context(
574        context: &mut gpu::DirectContext,
575        pixmap: &Pixmap,
576        build_mips: bool,
577        limit_to_max_texture_size: impl Into<Option<bool>>,
578    ) -> Option<Image> {
579        gpu::images::cross_context_texture_from_pixmap(
580            context,
581            pixmap,
582            build_mips,
583            limit_to_max_texture_size,
584        )
585    }
586
587    /// Creates [`Image`] from pixmap. [`Image`] is uploaded to GPU back-end using context.
588    ///
589    /// Created [`Image`] is available to other GPU contexts, and is available across thread
590    /// boundaries. All contexts must be in the same GPU share group, or otherwise
591    /// share resources.
592    ///
593    /// When [`Image`] is no longer referenced, context releases texture memory
594    /// asynchronously.
595    ///
596    /// [`ColorSpace`] of [`Image`] is determined by `pixmap.color_space()`.
597    ///
598    /// [`Image`] is returned referring to GPU back-end if context is not `None`,
599    /// format of data is recognized and supported, and if context supports moving
600    /// resources between contexts. Otherwise, pixmap pixel data is copied and [`Image`]
601    /// as returned in raster format if possible; `None` may be returned.
602    /// Recognized GPU formats vary by platform and GPU back-end.
603    ///
604    /// - `context`                 GPU context
605    /// - `pixmap`                  [`ImageInfo`], pixel address, and row bytes
606    /// - `build_mips`               create [`Image`] as mip map if `true`
607    /// - `limit_to_max_texture_size`   downscale image to GPU maximum texture size, if necessary
608    ///
609    /// Returns: created [`Image`], or `None`
610    #[cfg(feature = "gpu")]
611    #[deprecated(
612        since = "0.63.0",
613        note = "use gpu::images::cross_context_texture_from_pixmap()"
614    )]
615    pub fn new_cross_context_from_pixmap(
616        context: &mut gpu::DirectContext,
617        pixmap: &Pixmap,
618        build_mips: bool,
619        limit_to_max_texture_size: impl Into<Option<bool>>,
620    ) -> Option<Image> {
621        gpu::images::cross_context_texture_from_pixmap(
622            context,
623            pixmap,
624            build_mips,
625            limit_to_max_texture_size,
626        )
627    }
628
629    /// Creates [`Image`] from `backend_texture` associated with context. `backend_texture` and
630    /// returned [`Image`] are managed internally, and are released when no longer needed.
631    ///
632    /// [`Image`] is returned if format of `backend_texture` is recognized and supported.
633    /// Recognized formats vary by GPU back-end.
634    ///
635    /// - `context`          GPU context
636    /// - `backend_texture`   texture residing on GPU
637    /// - `texture_origin`    origin of `backend_texture`
638    /// - `color_type`        color type of the resulting image
639    /// - `alpha_type`        alpha type of the resulting image
640    /// - `color_space`       range of colors; may be `None`
641    ///
642    /// Returns: created [`Image`], or `None`
643    #[cfg(feature = "gpu")]
644    #[deprecated(since = "0.63.0", note = "use gpu::images::adopt_texture_from()")]
645    pub fn from_adopted_texture(
646        context: &mut gpu::RecordingContext,
647        backend_texture: &gpu::BackendTexture,
648        texture_origin: gpu::SurfaceOrigin,
649        color_type: ColorType,
650        alpha_type: impl Into<Option<AlphaType>>,
651        color_space: impl Into<Option<ColorSpace>>,
652    ) -> Option<Image> {
653        gpu::images::adopt_texture_from(
654            context,
655            backend_texture,
656            texture_origin,
657            color_type,
658            alpha_type,
659            color_space,
660        )
661    }
662
663    /// Creates an [`Image`] from `YUV[A]` planar textures. This requires that the textures stay valid
664    /// for the lifetime of the image. The `ReleaseContext` can be used to know when it is safe to
665    /// either delete or overwrite the textures. If `ReleaseProc` is provided it is also called before
666    /// return on failure.
667    ///
668    /// - `context`             GPU context
669    /// - `yuva_textures`        A set of textures containing YUVA data and a description of the
670    ///                           data and transformation to RGBA.
671    /// - `image_color_space`     range of colors of the resulting image after conversion to RGB;
672    ///                           may be `None`
673    /// - `texture_release_proc`  called when the backend textures can be released
674    /// - `release_context`      state passed to `texture_release_proc`
675    ///
676    /// Returns: created [`Image`], or `None`
677    #[cfg(feature = "gpu")]
678    #[deprecated(
679        since = "0.63.0",
680        note = "use gpu::images::texture_from_yuva_textures()"
681    )]
682    pub fn from_yuva_textures(
683        context: &mut gpu::RecordingContext,
684        yuva_textures: &gpu::YUVABackendTextures,
685        image_color_space: impl Into<Option<ColorSpace>>,
686    ) -> Option<Image> {
687        gpu::images::texture_from_yuva_textures(context, yuva_textures, image_color_space)
688    }
689
690    /// Creates [`Image`] from [`crate::YUVAPixmaps`].
691    ///
692    /// The image will remain planar with each plane converted to a texture using the passed
693    /// [`gpu::RecordingContext`].
694    ///
695    /// [`crate::YUVAPixmaps`] has a [`crate::YUVAInfo`] which specifies the transformation from YUV to RGB.
696    /// The [`ColorSpace`] of the resulting RGB values is specified by `image_color_space`. This will
697    /// be the [`ColorSpace`] reported by the image and when drawn the RGB values will be converted
698    /// from this space into the destination space (if the destination is tagged).
699    ///
700    /// Currently, this is only supported using the GPU backend and will fail if context is `None`.
701    ///
702    /// [`crate::YUVAPixmaps`] does not need to remain valid after this returns.
703    ///
704    /// - `context`                 GPU context
705    /// - `pixmaps`                 The planes as pixmaps with supported [`crate::YUVAInfo`] that
706    ///                               specifies conversion to RGB.
707    /// - `build_mips`               create internal YUVA textures as mip map if `Yes`. This is
708    ///                               silently ignored if the context does not support mip maps.
709    /// - `limit_to_max_texture_size`   downscale image to GPU maximum texture size, if necessary
710    /// - `image_color_space`         range of colors of the resulting image; may be `None`
711    ///
712    /// Returns: created [`Image`], or `None`
713    #[cfg(feature = "gpu")]
714    #[deprecated(
715        since = "0.63.0",
716        note = "use gpu::images::texture_from_yuva_pixmaps()"
717    )]
718    pub fn from_yuva_pixmaps(
719        context: &mut gpu::RecordingContext,
720        yuva_pixmaps: &crate::YUVAPixmaps,
721        build_mips: impl Into<Option<gpu::Mipmapped>>,
722        limit_to_max_texture_size: impl Into<Option<bool>>,
723        image_color_space: impl Into<Option<ColorSpace>>,
724    ) -> Option<Image> {
725        gpu::images::texture_from_yuva_pixmaps(
726            context,
727            yuva_pixmaps,
728            build_mips,
729            limit_to_max_texture_size,
730            image_color_space,
731        )
732    }
733
734    #[cfg(feature = "gpu")]
735    #[deprecated(since = "0.37.0", note = "Removed without replacement")]
736    pub fn from_nv12_textures_copy(
737        _context: &mut gpu::DirectContext,
738        _yuv_color_space: crate::YUVColorSpace,
739        _nv12_textures: &[gpu::BackendTexture; 2],
740        _image_origin: gpu::SurfaceOrigin,
741        _image_color_space: impl Into<Option<ColorSpace>>,
742    ) -> ! {
743        panic!("Removed without replacement")
744    }
745
746    /// Returns a [`ImageInfo`] describing the width, height, color type, alpha type, and color space
747    /// of the [`Image`].
748    ///
749    /// Returns: image info of [`Image`].
750    pub fn image_info(&self) -> &ImageInfo {
751        ImageInfo::from_native_ref(&self.native().fInfo)
752    }
753
754    /// Returns pixel count in each row.
755    ///
756    /// Returns: pixel width in [`Image`]
757    pub fn width(&self) -> i32 {
758        self.image_info().width()
759    }
760
761    /// Returns pixel row count.
762    ///
763    /// Returns: pixel height in [`Image`]
764    pub fn height(&self) -> i32 {
765        self.image_info().height()
766    }
767
768    /// Returns [`ISize`] `{ width(), height() }`.
769    ///
770    /// Returns: integral size of `width()` and `height()`
771    pub fn dimensions(&self) -> ISize {
772        self.image_info().dimensions()
773    }
774
775    /// Returns [`IRect`] `{ 0, 0, width(), height() }`.
776    ///
777    /// Returns: integral rectangle from origin to `width()` and `height()`
778    pub fn bounds(&self) -> IRect {
779        self.image_info().bounds()
780    }
781
782    /// Returns value unique to image. [`Image`] contents cannot change after [`Image`] is
783    /// created. Any operation to create a new [`Image`] will receive generate a new
784    /// unique number.
785    ///
786    /// Returns: unique identifier
787    pub fn unique_id(&self) -> u32 {
788        self.native().fUniqueID
789    }
790
791    /// Returns [`AlphaType`].
792    ///
793    /// [`AlphaType`] returned was a parameter to an [`Image`] constructor,
794    /// or was parsed from encoded data.
795    ///
796    /// Returns: [`AlphaType`] in [`Image`]
797    ///
798    /// example: <https://fiddle.skia.org/c/@Image_alphaType>
799    pub fn alpha_type(&self) -> AlphaType {
800        unsafe { self.native().alphaType() }
801    }
802
803    /// Returns [`ColorType`] if known; otherwise, returns [`ColorType::Unknown`].
804    ///
805    /// Returns: [`ColorType`] of [`Image`]
806    ///
807    /// example: <https://fiddle.skia.org/c/@Image_colorType>
808    pub fn color_type(&self) -> ColorType {
809        ColorType::from_native_c(unsafe { self.native().colorType() })
810    }
811
812    /// Returns a smart pointer to [`ColorSpace`], the range of colors, associated with
813    /// [`Image`].  The smart pointer tracks the number of objects sharing this
814    /// [`ColorSpace`] reference so the memory is released when the owners destruct.
815    ///
816    /// The returned [`ColorSpace`] is immutable.
817    ///
818    /// [`ColorSpace`] returned was passed to an [`Image`] constructor,
819    /// or was parsed from encoded data. [`ColorSpace`] returned may be ignored when [`Image`]
820    /// is drawn, depending on the capabilities of the [`crate::Surface`] receiving the drawing.
821    ///
822    /// Returns: [`ColorSpace`] in [`Image`], or `None`, wrapped in a smart pointer
823    ///
824    /// example: <https://fiddle.skia.org/c/@Image_refColorSpace>
825    pub fn color_space(&self) -> ColorSpace {
826        ColorSpace::from_unshared_ptr(unsafe { self.native().colorSpace() }).unwrap()
827    }
828
829    /// Returns `true` if [`Image`] pixels represent transparency only. If `true`, each pixel
830    /// is packed in 8 bits as defined by [`ColorType::Alpha8`].
831    ///
832    /// Returns: `true` if pixels represent a transparency mask
833    ///
834    /// example: <https://fiddle.skia.org/c/@Image_isAlphaOnly>
835    pub fn is_alpha_only(&self) -> bool {
836        unsafe { self.native().isAlphaOnly() }
837    }
838
839    /// Returns `true` if pixels ignore their alpha value and are treated as fully opaque.
840    ///
841    /// Returns: `true` if [`AlphaType`] is [`AlphaType::Opaque`]
842    pub fn is_opaque(&self) -> bool {
843        self.alpha_type().is_opaque()
844    }
845
846    /// Make a shader with the specified tiling and mipmap sampling.
847    pub fn to_shader<'a>(
848        &self,
849        tile_modes: impl Into<Option<(TileMode, TileMode)>>,
850        sampling: impl Into<SamplingOptions>,
851        local_matrix: impl Into<Option<&'a Matrix>>,
852    ) -> Option<Shader> {
853        let tile_modes = tile_modes.into();
854        let tm1 = tile_modes.map(|(tm, _)| tm).unwrap_or_default();
855        let tm2 = tile_modes.map(|(_, tm)| tm).unwrap_or_default();
856        let sampling = sampling.into();
857
858        Shader::from_ptr(unsafe {
859            sb::C_SkImage_makeShader(
860                self.native(),
861                tm1,
862                tm2,
863                sampling.native(),
864                local_matrix.into().native_ptr_or_null(),
865            )
866        })
867    }
868
869    /// `to_raw_shader` functions like `to_shader`, but for images that contain non-color data.
870    /// This includes images encoding things like normals, material properties (eg, roughness),
871    /// heightmaps, or any other purely mathematical data that happens to be stored in an image.
872    /// These types of images are useful with some programmable shaders (see: [`crate::RuntimeEffect`]).
873    ///
874    /// Raw image shaders work like regular image shaders (including filtering and tiling), with
875    /// a few major differences:
876    ///   - No color space transformation is ever applied (the color space of the image is ignored).
877    ///   - Images with an alpha type of `Unpremul` are *not* automatically premultiplied.
878    ///   - Bicubic filtering is not supported. If [`SamplingOptions::use_cubic`] is `true`, these
879    ///     factories will return `None`.
880    pub fn to_raw_shader<'a>(
881        &self,
882        tile_modes: impl Into<Option<(TileMode, TileMode)>>,
883        sampling: impl Into<SamplingOptions>,
884        local_matrix: impl Into<Option<&'a Matrix>>,
885    ) -> Option<Shader> {
886        let tile_modes = tile_modes.into();
887        let tm1 = tile_modes.map(|(tm, _)| tm).unwrap_or_default();
888        let tm2 = tile_modes.map(|(_, tm)| tm).unwrap_or_default();
889        let sampling = sampling.into();
890
891        Shader::from_ptr(unsafe {
892            sb::C_SkImage_makeRawShader(
893                self.native(),
894                tm1,
895                tm2,
896                sampling.native(),
897                local_matrix.into().native_ptr_or_null(),
898            )
899        })
900    }
901
902    /// Copies [`Image`] pixel address, row bytes, and [`ImageInfo`] to pixmap, if address
903    /// is available, and returns `true`. If pixel address is not available, return
904    /// `false` and leave pixmap unchanged.
905    ///
906    /// - `pixmap`   storage for pixel state if pixels are readable; otherwise, ignored
907    ///
908    /// Returns: `true` if [`Image`] has direct access to pixels
909    ///
910    /// example: <https://fiddle.skia.org/c/@Image_peekPixels>
911    pub fn peek_pixels(&self) -> Option<Pixmap> {
912        let mut pixmap = Pixmap::default();
913        unsafe { self.native().peekPixels(pixmap.native_mut()) }.if_true_some(pixmap)
914    }
915
916    /// Returns `true` if the contents of [`Image`] was created on or uploaded to GPU memory,
917    /// and is available as a GPU texture.
918    ///
919    /// Returns: `true` if [`Image`] is a GPU texture
920    ///
921    /// example: <https://fiddle.skia.org/c/@Image_isTextureBacked>
922    pub fn is_texture_backed(&self) -> bool {
923        unsafe { sb::C_SkImage_isTextureBacked(self.native()) }
924    }
925
926    /// Returns an approximation of the amount of texture memory used by the image. Returns
927    /// zero if the image is not texture backed or if the texture has an external format.
928    pub fn texture_size(&self) -> usize {
929        unsafe { sb::C_SkImage_textureSize(self.native()) }
930    }
931
932    /// Returns `true` if [`Image`] can be drawn on either raster surface or GPU surface.
933    /// If context is `None`, tests if [`Image`] draws on raster surface;
934    /// otherwise, tests if [`Image`] draws on GPU surface associated with context.
935    ///
936    /// [`Image`] backed by GPU texture may become invalid if associated context is
937    /// invalid. lazy image may be invalid and may not draw to raster surface or
938    /// GPU surface or both.
939    ///
940    /// - `context`   GPU context
941    ///
942    /// Returns: `true` if [`Image`] can be drawn
943    ///
944    /// example: <https://fiddle.skia.org/c/@Image_isValid>
945    #[cfg(feature = "gpu")]
946    pub fn is_valid(&self, context: &mut gpu::RecordingContext) -> bool {
947        unsafe { sb::C_SkImage_isValid(self.native(), context.native_mut()) }
948    }
949
950    /// Create a new image by copying this image and scaling to fit the [`ImageInfo`]'s dimensions
951    /// and converting the pixels into the ImageInfo's [`crate::ColorInfo`].
952    ///
953    /// This is done retaining the domain (backend) of the image (e.g. gpu, raster).
954    ///
955    /// Returns `None` if the requested [`crate::ColorInfo`] is not supported, its dimensions are out
956    /// of range.
957    pub fn make_scaled(
958        &self,
959        info: &ImageInfo,
960        scaling: impl Into<SamplingOptions>,
961    ) -> Option<Image> {
962        Image::from_ptr(unsafe {
963            sb::C_SkImage_makeScaled(self.native(), info.native(), scaling.into().native())
964        })
965    }
966
967    /// See [`Self::flush_with_info()`]
968    #[cfg(feature = "gpu")]
969    #[deprecated(since = "0.63.0", note = "use gpu::DirectContext::flush()")]
970    pub fn flush<'a>(
971        &self,
972        context: &mut gpu::DirectContext,
973        flush_info: impl Into<Option<&'a gpu::FlushInfo>>,
974    ) -> gpu::SemaphoresSubmitted {
975        context.flush(flush_info)
976    }
977
978    /// Flushes any pending uses of texture-backed images in the GPU backend. If the image is not
979    /// texture-backed (including promise texture images) or if the [`gpu::DirectContext`] does not
980    /// have the same context ID as the context backing the image then this is a no-op.
981    ///
982    /// If the image was not used in any non-culled draws in the current queue of work for the
983    /// passed [`gpu::DirectContext`] then this is a no-op unless the [`gpu::FlushInfo`] contains semaphores or
984    /// a finish proc. Those are respected even when the image has not been used.
985    ///
986    /// - `context`   the context on which to flush pending usages of the image.
987    /// - `info`      flush options
988    #[cfg(feature = "gpu")]
989    #[deprecated(since = "0.46.0", note = "use gpu::DirectContext::flush()")]
990    pub fn flush_with_info(
991        &self,
992        context: &mut gpu::DirectContext,
993        flush_info: &gpu::FlushInfo,
994    ) -> gpu::SemaphoresSubmitted {
995        context.flush(flush_info)
996    }
997
998    /// Version of `flush()` that uses a default [`gpu::FlushInfo`]. Also submits the flushed work to the
999    /// GPU.
1000    #[cfg(feature = "gpu")]
1001    #[deprecated(since = "0.63.0", note = "use gpu::DirectContext::flush_and_submit()")]
1002    pub fn flush_and_submit(&self, context: &mut gpu::DirectContext) {
1003        context.flush_and_submit();
1004    }
1005
1006    /// Retrieves the back-end texture. If [`Image`] has no back-end texture, `None`is returned.
1007    ///
1008    /// If `flush_pending_gr_context_io` is `true`, completes deferred I/O operations.
1009    ///
1010    /// If origin in not `None`, copies location of content drawn into [`Image`].
1011    ///
1012    /// - `flush_pending_gr_context_io`   flag to flush outstanding requests
1013    ///
1014    /// Returns: back-end API texture handle; invalid on failure
1015    #[cfg(feature = "gpu")]
1016    #[deprecated(
1017        since = "0.63.0",
1018        note = "use gpu::images::get_backend_texture_from_image()"
1019    )]
1020    pub fn backend_texture(
1021        &self,
1022        flush_pending_gr_context_io: bool,
1023    ) -> Option<(gpu::BackendTexture, gpu::SurfaceOrigin)> {
1024        gpu::images::get_backend_texture_from_image(self, flush_pending_gr_context_io)
1025    }
1026
1027    /// Copies [`crate::Rect`] of pixels from [`Image`] to `dst_pixels`. Copy starts at offset (`src_x`, `src_y`),
1028    /// and does not exceed [`Image`] (width(), height()).
1029    ///
1030    /// Graphite has deprecated this API in favor of the equivalent asynchronous API on
1031    /// `skgpu::graphite::Context` (with an optional explicit synchronization).
1032    ///
1033    /// `dst_info` specifies width, height, [`ColorType`], [`AlphaType`], and [`ColorSpace`] of
1034    /// destination. `dst_row_bytes` specifies the gap from one destination row to the next.
1035    /// Returns `true` if pixels are copied. Returns `false` if:
1036    /// - `dst_info`.`addr()` equals `None`
1037    /// - `dst_row_bytes` is less than `dst_info.min_row_bytes()`
1038    /// - [`crate::PixelRef`] is `None`
1039    ///
1040    /// Pixels are copied only if pixel conversion is possible. If [`Image`] [`ColorType`] is
1041    /// [`ColorType::Gray8`], or [`ColorType::Alpha8`]; `dst_info.color_type()` must match.
1042    /// If [`Image`] [`ColorType`] is [`ColorType::Gray8`], `dst_info`.`color_space()` must match.
1043    /// If [`Image`] [`AlphaType`] is [`AlphaType::Opaque`], `dst_info`.`alpha_type()` must
1044    /// match. If [`Image`] [`ColorSpace`] is `None`, `dst_info.color_space()` must match. Returns
1045    /// `false` if pixel conversion is not possible.
1046    ///
1047    /// `src_x` and `src_y` may be negative to copy only top or left of source. Returns
1048    /// `false` if `width()` or `height()` is zero or negative.
1049    /// Returns `false` if abs(`src_x`) >= Image width(), or if abs(`src_y`) >= Image height().
1050    ///
1051    /// If `caching_hint` is [`CachingHint::Allow`], pixels may be retained locally.
1052    /// If `caching_hint` is [`CachingHint::Disallow`], pixels are not added to the local cache.
1053    ///
1054    /// - `context`       the [`gpu::DirectContext`] in play, if it exists
1055    /// - `dst_info`       destination width, height, [`ColorType`], [`AlphaType`], [`ColorSpace`]
1056    /// - `dst_pixels`     destination pixel storage
1057    /// - `dst_row_bytes`   destination row length
1058    /// - `src_x`          column index whose absolute value is less than `width()`
1059    /// - `src_y`          row index whose absolute value is less than `height()`
1060    /// - `caching_hint`   whether the pixels should be cached locally
1061    ///
1062    /// Returns: `true` if pixels are copied to `dst_pixels`
1063    #[cfg(feature = "gpu")]
1064    pub fn read_pixels_with_context<'a, P>(
1065        &self,
1066        context: impl Into<Option<&'a mut gpu::DirectContext>>,
1067        dst_info: &ImageInfo,
1068        pixels: &mut [P],
1069        dst_row_bytes: usize,
1070        src: impl Into<IPoint>,
1071        caching_hint: CachingHint,
1072    ) -> bool {
1073        if !dst_info.valid_pixels(dst_row_bytes, pixels) {
1074            return false;
1075        }
1076
1077        let src = src.into();
1078
1079        unsafe {
1080            self.native().readPixels(
1081                context.into().native_ptr_or_null_mut(),
1082                dst_info.native(),
1083                pixels.as_mut_ptr() as _,
1084                dst_row_bytes,
1085                src.x,
1086                src.y,
1087                caching_hint,
1088            )
1089        }
1090    }
1091
1092    /// Copies a [`crate::Rect`] of pixels from [`Image`] to dst. Copy starts at (`src_x`, `src_y`), and
1093    /// does not exceed [`Image`] (width(), height()).
1094    ///
1095    /// Graphite has deprecated this API in favor of the equivalent asynchronous API on
1096    /// `skgpu::graphite::Context` (with an optional explicit synchronization).
1097    ///
1098    /// dst specifies width, height, [`ColorType`], [`AlphaType`], [`ColorSpace`], pixel storage,
1099    /// and row bytes of destination. dst.`row_bytes()` specifics the gap from one destination
1100    /// row to the next. Returns `true` if pixels are copied. Returns `false` if:
1101    /// - dst pixel storage equals `None`
1102    /// - dst.`row_bytes` is less than [`ImageInfo::min_row_bytes`]
1103    /// - [`crate::PixelRef`] is `None`
1104    ///
1105    /// Pixels are copied only if pixel conversion is possible. If [`Image`] [`ColorType`] is
1106    /// [`ColorType::Gray8`], or [`ColorType::Alpha8`]; dst.`color_type()` must match.
1107    /// If [`Image`] [`ColorType`] is [`ColorType::Gray8`], dst.`color_space()` must match.
1108    /// If [`Image`] [`AlphaType`] is [`AlphaType::Opaque`], dst.`alpha_type()` must
1109    /// match. If [`Image`] [`ColorSpace`] is `None`, dst.`color_space()` must match. Returns
1110    /// `false` if pixel conversion is not possible.
1111    ///
1112    /// `src_x` and `src_y` may be negative to copy only top or left of source. Returns
1113    /// `false` if `width()` or `height()` is zero or negative.
1114    /// Returns `false` if abs(`src_x`) >= Image width(), or if abs(`src_y`) >= Image height().
1115    ///
1116    /// If `caching_hint` is [`CachingHint::Allow`], pixels may be retained locally.
1117    /// If `caching_hint` is [`CachingHint::Disallow`], pixels are not added to the local cache.
1118    ///
1119    /// - `context`       the [`gpu::DirectContext`] in play, if it exists
1120    /// - `dst`           destination [`Pixmap`]:[`ImageInfo`], pixels, row bytes
1121    /// - `src_x`          column index whose absolute value is less than `width()`
1122    /// - `src_y`          row index whose absolute value is less than `height()`
1123    /// - `caching_hint`   whether the pixels should be cached `locally_z`
1124    ///
1125    /// Returns: `true` if pixels are copied to dst
1126    #[cfg(feature = "gpu")]
1127    pub fn read_pixels_to_pixmap_with_context<'a>(
1128        &self,
1129        context: impl Into<Option<&'a mut gpu::DirectContext>>,
1130        dst: &Pixmap,
1131        src: impl Into<IPoint>,
1132        caching_hint: CachingHint,
1133    ) -> bool {
1134        let src = src.into();
1135
1136        unsafe {
1137            self.native().readPixels1(
1138                context.into().native_ptr_or_null_mut(),
1139                dst.native(),
1140                src.x,
1141                src.y,
1142                caching_hint,
1143            )
1144        }
1145    }
1146
1147    // _not_ deprecated, because we support separate functions in `gpu` feature builds.
1148    /// See [`Self::read_pixels_with_context()`]
1149    pub fn read_pixels<P>(
1150        &self,
1151        dst_info: &ImageInfo,
1152        pixels: &mut [P],
1153        dst_row_bytes: usize,
1154        src: impl Into<IPoint>,
1155        caching_hint: CachingHint,
1156    ) -> bool {
1157        if !dst_info.valid_pixels(dst_row_bytes, pixels) {
1158            return false;
1159        }
1160
1161        let src = src.into();
1162
1163        unsafe {
1164            self.native().readPixels(
1165                ptr::null_mut(),
1166                dst_info.native(),
1167                pixels.as_mut_ptr() as _,
1168                dst_row_bytes,
1169                src.x,
1170                src.y,
1171                caching_hint,
1172            )
1173        }
1174    }
1175
1176    /// See [`Self::read_pixels_to_pixmap_with_context()`]
1177    #[cfg(feature = "gpu")]
1178    #[allow(clippy::missing_safety_doc)]
1179    pub unsafe fn read_pixels_to_pixmap(
1180        &self,
1181        dst: &Pixmap,
1182        src: impl Into<IPoint>,
1183        caching_hint: CachingHint,
1184    ) -> bool {
1185        let src = src.into();
1186
1187        self.native()
1188            .readPixels1(ptr::null_mut(), dst.native(), src.x, src.y, caching_hint)
1189    }
1190
1191    // TODO:
1192    // AsyncReadResult,
1193    // ReadPixelsContext,
1194    // ReadPixelsCallback,
1195    // RescaleGamma,
1196    // RescaleMode,
1197    // asyncRescaleAndReadPixels,
1198    // asyncRescaleAndReadPixelsYUV420,
1199    // asyncRescaleAndReadPixelsYUVA420
1200
1201    /// Copies [`Image`] to dst, scaling pixels to fit `dst.width()` and `dst.height()`, and
1202    /// converting pixels to match `dst.color_type()` and `dst.alpha_type()`. Returns `true` if
1203    /// pixels are copied. Returns `false` if `dst.addr()` is `None`, or `dst.row_bytes()` is
1204    /// less than dst [`ImageInfo::min_row_bytes`].
1205    ///
1206    /// Pixels are copied only if pixel conversion is possible. If [`Image`] [`ColorType`] is
1207    /// [`ColorType::Gray8`], or [`ColorType::Alpha8`]; `dst.color_type()` must match.
1208    /// If [`Image`] [`ColorType`] is [`ColorType::Gray8`], `dst.color_space()` must match.
1209    /// If [`Image`] [`AlphaType`] is [`AlphaType::Opaque`], `dst.alpha_type()` must
1210    /// match. If [`Image`] [`ColorSpace`] is `None`, `dst.color_space()` must match. Returns
1211    /// `false` if pixel conversion is not possible.
1212    ///
1213    /// If `caching_hint` is [`CachingHint::Allow`], pixels may be retained locally.
1214    /// If `caching_hint` is [`CachingHint::Disallow`], pixels are not added to the local cache.
1215    ///
1216    /// - `dst`             destination [`Pixmap`]:[`ImageInfo`], pixels, row bytes
1217    ///
1218    /// Returns: `true` if pixels are scaled to fit dst
1219    #[must_use]
1220    pub fn scale_pixels(
1221        &self,
1222        dst: &Pixmap,
1223        sampling: impl Into<SamplingOptions>,
1224        caching_hint: impl Into<Option<CachingHint>>,
1225    ) -> bool {
1226        unsafe {
1227            self.native().scalePixels(
1228                dst.native(),
1229                sampling.into().native(),
1230                caching_hint.into().unwrap_or(CachingHint::Allow),
1231            )
1232        }
1233    }
1234
1235    /// Encodes [`Image`] pixels, returning result as [`Data`].
1236    ///
1237    ///  Returns `None` if encoding fails, or if `encoded_image_format` is not supported.
1238    ///
1239    ///  [`Image`] encoding in a format requires both building with one or more of:
1240    ///  SK_ENCODE_JPEG, SK_ENCODE_PNG, SK_ENCODE_WEBP; and platform support
1241    ///  for the encoded format.
1242    ///
1243    ///  If SK_BUILD_FOR_MAC or SK_BUILD_FOR_IOS is defined, `encoded_image_format` can
1244    ///  additionally be one of: [`EncodedImageFormat::ICO`], [`EncodedImageFormat::BMP`],
1245    ///  [`EncodedImageFormat::GIF`].
1246    ///
1247    ///  quality is a platform and format specific metric trading off size and encoding
1248    ///  error. When used, quality equaling 100 encodes with the least error. quality may
1249    ///  be ignored by the encoder.
1250    ///
1251    ///  * `context` - the [`gpu::DirectContext`] in play, if it exists; can be `None`
1252    ///  * `encoded_image_format` - one of: [`EncodedImageFormat::JPEG`], [`EncodedImageFormat::PNG`],
1253    ///                             [`EncodedImageFormat::WEBP`]
1254    ///  * `quality` - encoder specific metric with 100 equaling best
1255    ///
1256    ///  Returns: encoded [`Image`], or `None`
1257    ///
1258    ///  example: <https://fiddle.skia.org/c/@Image_encodeToData>
1259    #[cfg(feature = "gpu")]
1260    #[deprecated(since = "0.63.0", note = "Use encode")]
1261    pub fn encode_to_data_with_context(
1262        &self,
1263        context: impl Into<Option<gpu::DirectContext>>,
1264        image_format: EncodedImageFormat,
1265        quality: impl Into<Option<u32>>,
1266    ) -> Option<Data> {
1267        let mut context = context.into();
1268        self.encode(context.as_mut(), image_format, quality)
1269    }
1270
1271    /// See [`Self::encode_to_data_with_quality`]
1272    #[deprecated(
1273        since = "0.63.0",
1274        note = "Support for encoding GPU backed images without a context was removed, use `encode_to_data_with_context` instead"
1275    )]
1276    pub fn encode_to_data(&self, image_format: EncodedImageFormat) -> Option<Data> {
1277        self.encode(None, image_format, 100)
1278    }
1279
1280    /// Encodes [`Image`] pixels, returning result as [`Data`].
1281    ///
1282    /// Returns `None` if encoding fails, or if `encoded_image_format` is not supported.
1283    ///
1284    /// [`Image`] encoding in a format requires both building with one or more of:
1285    /// SK_ENCODE_JPEG, SK_ENCODE_PNG, SK_ENCODE_WEBP; and platform support
1286    /// for the encoded format.
1287    ///
1288    /// If SK_BUILD_FOR_MAC or SK_BUILD_FOR_IOS is defined, `encoded_image_format` can
1289    /// additionally be one of: [`EncodedImageFormat::ICO`], [`EncodedImageFormat::BMP`],
1290    /// [`EncodedImageFormat::GIF`].
1291    ///
1292    /// quality is a platform and format specific metric trading off size and encoding
1293    /// error. When used, quality equaling 100 encodes with the least error. quality may
1294    /// be ignored by the encoder.
1295    ///
1296    /// - `encoded_image_format`   one of: [`EncodedImageFormat::JPEG`], [`EncodedImageFormat::PNG`],
1297    ///                            [`EncodedImageFormat::WEBP`]
1298    /// - `quality`              encoder specific metric with 100 equaling best
1299    ///
1300    /// Returns: encoded [`Image`], or `None`
1301    ///
1302    /// example: <https://fiddle.skia.org/c/@Image_encodeToData>
1303    #[deprecated(
1304        since = "0.63.0",
1305        note = "Support for encoding GPU backed images without a context was removed, use `encode_to_data_with_context` instead"
1306    )]
1307    pub fn encode_to_data_with_quality(
1308        &self,
1309        image_format: EncodedImageFormat,
1310        quality: u32,
1311    ) -> Option<Data> {
1312        self.encode(None, image_format, quality)
1313    }
1314
1315    /// Returns encoded [`Image`] pixels as [`Data`], if [`Image`] was created from supported
1316    /// encoded stream format. Platform support for formats vary and may require building
1317    /// with one or more of: SK_ENCODE_JPEG, SK_ENCODE_PNG, SK_ENCODE_WEBP.
1318    ///
1319    /// Returns `None` if [`Image`] contents are not encoded.
1320    ///
1321    /// Returns: encoded [`Image`], or `None`
1322    ///
1323    /// example: <https://fiddle.skia.org/c/@Image_refEncodedData>
1324    pub fn encoded_data(&self) -> Option<Data> {
1325        Data::from_ptr(unsafe { sb::C_SkImage_refEncodedData(self.native()) })
1326    }
1327
1328    /// See [`Self::new_subset_with_context`]
1329    #[deprecated(since = "0.64.0", note = "use make_subset()")]
1330    pub fn new_subset(&self, rect: impl AsRef<IRect>) -> Option<Image> {
1331        self.make_subset(None, rect)
1332    }
1333
1334    /// Returns subset of this image.
1335    ///
1336    /// Returns `None` if any of the following are true:
1337    ///   - Subset is empty
1338    ///   - Subset is not contained inside the image's bounds
1339    ///   - Pixels in the image could not be read or copied
1340    ///
1341    /// If this image is texture-backed, the context parameter is required and must match the
1342    /// context of the source image. If the context parameter is provided, and the image is
1343    /// raster-backed, the subset will be converted to texture-backed.
1344    ///
1345    /// - `subset`   bounds of returned [`Image`]
1346    /// - `context`  the [`gpu::DirectContext`] in play, if it exists
1347    ///
1348    /// Returns: the subsetted image, or `None`
1349    ///
1350    /// example: <https://fiddle.skia.org/c/@Image_makeSubset>
1351    #[cfg(feature = "gpu")]
1352    #[deprecated(since = "0.64.0", note = "use make_subset()")]
1353    pub fn new_subset_with_context<'a>(
1354        &self,
1355        rect: impl AsRef<IRect>,
1356        direct: impl Into<Option<&'a mut gpu::DirectContext>>,
1357    ) -> Option<Image> {
1358        self.make_subset(direct, rect)
1359    }
1360
1361    /// Returns subset of this image.
1362    ///
1363    /// Returns `None` if any of the following are true:
1364    ///     - Subset is empty - Subset is not contained inside the image's bounds
1365    ///     - Pixels in the source image could not be read or copied
1366    ///     - This image is texture-backed and the provided context is null or does not match the
1367    ///     source image's context.
1368    ///
1369    /// If the source image was texture-backed, the resulting image will be texture-backed also.
1370    /// Otherwise, the returned image will be raster-backed.
1371    ///
1372    /// * `direct` - the [`gpu::DirectContext`] of the source image (`None` is ok if the source
1373    ///                 image is not texture-backed).
1374    /// * `subset` - bounds of returned [`Image`] Returns: the subsetted image, or `None`
1375    ///
1376    /// example: <https://fiddle.skia.org/c/@Image_makeSubset>
1377    pub fn make_subset<'a>(
1378        &self,
1379        direct: impl Into<Option<&'a mut gpu::DirectContext>>,
1380        subset: impl AsRef<IRect>,
1381    ) -> Option<Image> {
1382        Image::from_ptr(unsafe {
1383            sb::C_SkImage_makeSubset(
1384                self.native(),
1385                direct.into().native_ptr_or_null_mut(),
1386                subset.as_ref().native(),
1387            )
1388        })
1389    }
1390
1391    /// Returns `true` if the image has mipmap levels.
1392    pub fn has_mipmaps(&self) -> bool {
1393        unsafe { self.native().hasMipmaps() }
1394    }
1395
1396    /// Returns an image with the same "base" pixels as the this image, but with mipmap levels
1397    /// automatically generated and attached.
1398    pub fn with_default_mipmaps(&self) -> Option<Image> {
1399        Image::from_ptr(unsafe { sb::C_SkImage_withDefaultMipmaps(self.native()) })
1400    }
1401
1402    /// See [`Self::new_texture_image_budgeted`]
1403    #[cfg(feature = "gpu")]
1404    pub fn new_texture_image(
1405        &self,
1406        context: &mut gpu::DirectContext,
1407        mipmapped: gpu::Mipmapped,
1408    ) -> Option<Image> {
1409        self.new_texture_image_budgeted(context, mipmapped, gpu::Budgeted::Yes)
1410    }
1411
1412    /// Returns [`Image`] backed by GPU texture associated with context. Returned [`Image`] is
1413    /// compatible with [`crate::Surface`] created with `dst_color_space`. The returned [`Image`] respects
1414    /// mipmapped setting; if mipmapped equals [`gpu::Mipmapped::Yes`], the backing texture
1415    /// allocates mip map levels.
1416    ///
1417    /// The mipmapped parameter is effectively treated as `No` if MIP maps are not supported by the
1418    /// GPU.
1419    ///
1420    /// Returns original [`Image`] if the image is already texture-backed, the context matches, and
1421    /// mipmapped is compatible with the backing GPU texture. [`crate::Budgeted`] is ignored in this case.
1422    ///
1423    /// Returns `None` if context is `None`, or if [`Image`] was created with another
1424    /// [`gpu::DirectContext`].
1425    ///
1426    /// - `direct_context`  the [`gpu::DirectContext`] in play, if it exists
1427    /// - `mipmapped`      whether created [`Image`] texture must allocate mip map levels
1428    /// - `budgeted`       whether to count a newly created texture for the returned image
1429    ///                     counts against the context's budget.
1430    ///
1431    /// Returns: created [`Image`], or `None`
1432    #[cfg(feature = "gpu")]
1433    pub fn new_texture_image_budgeted(
1434        &self,
1435        direct_context: &mut gpu::DirectContext,
1436        mipmapped: gpu::Mipmapped,
1437        budgeted: gpu::Budgeted,
1438    ) -> Option<Image> {
1439        gpu::images::texture_from_image(direct_context, self, mipmapped, budgeted)
1440    }
1441
1442    /// Returns raster image or lazy image. Copies [`Image`] backed by GPU texture into
1443    /// CPU memory if needed. Returns original [`Image`] if decoded in raster bitmap,
1444    /// or if encoded in a stream.
1445    ///
1446    /// Returns `None` if backed by GPU texture and copy fails.
1447    ///
1448    /// Returns: raster image, lazy image, or `None`
1449    ///
1450    /// example: <https://fiddle.skia.org/c/@Image_makeNonTextureImage>
1451    #[deprecated(since = "0.64.0", note = "use make_non_texture_image()")]
1452    pub fn to_non_texture_image(&self) -> Option<Image> {
1453        Image::from_ptr(unsafe {
1454            sb::C_SkImage_makeNonTextureImage(self.native(), ptr::null_mut())
1455        })
1456    }
1457
1458    /// Returns raster image or lazy image. Copies [`Image`] backed by GPU texture into
1459    /// CPU memory if needed. Returns original [`Image`] if decoded in raster bitmap,
1460    /// or if encoded in a stream.
1461    ///
1462    /// Returns `None` if backed by GPU texture and copy fails.
1463    ///
1464    /// Returns: raster image, lazy image, or `None`
1465    ///
1466    /// example: <https://fiddle.skia.org/c/@Image_makeNonTextureImage>
1467    pub fn make_non_texture_image<'a>(
1468        &self,
1469        context: impl Into<Option<&'a mut gpu::DirectContext>>,
1470    ) -> Option<Image> {
1471        Image::from_ptr(unsafe {
1472            sb::C_SkImage_makeNonTextureImage(
1473                self.native(),
1474                context.into().native_ptr_or_null_mut(),
1475            )
1476        })
1477    }
1478
1479    /// Returns raster image. Copies [`Image`] backed by GPU texture into CPU memory,
1480    /// or decodes [`Image`] from lazy image. Returns original [`Image`] if decoded in
1481    /// raster bitmap.
1482    ///
1483    /// Returns `None` if copy, decode, or pixel read fails.
1484    ///
1485    /// If `caching_hint` is [`CachingHint::Allow`], pixels may be retained locally.
1486    /// If `caching_hint` is [`CachingHint::Disallow`], pixels are not added to the local cache.
1487    ///
1488    /// Returns: raster image, or `None`
1489    ///
1490    /// example: <https://fiddle.skia.org/c/@Image_makeRasterImage>
1491    #[deprecated(since = "0.64.0", note = "use make_raster_image()")]
1492    pub fn to_raster_image(&self, caching_hint: impl Into<Option<CachingHint>>) -> Option<Image> {
1493        let caching_hint = caching_hint.into().unwrap_or(CachingHint::Disallow);
1494        Image::from_ptr(unsafe {
1495            sb::C_SkImage_makeRasterImage(self.native(), ptr::null_mut(), caching_hint)
1496        })
1497    }
1498
1499    /// Returns raster image. Copies [`Image`] backed by GPU texture into CPU memory,
1500    /// or decodes [`Image`] from lazy image. Returns original [`Image`] if decoded in
1501    /// raster bitmap.
1502    ///
1503    /// Returns `None` if copy, decode, or pixel read fails.
1504    ///
1505    /// If `caching_hint` is [`CachingHint::Allow`], pixels may be retained locally.
1506    /// If `caching_hint` is [`CachingHint::Disallow`], pixels are not added to the local cache.
1507    ///
1508    /// Returns: raster image, or `None`
1509    ///
1510    /// example: <https://fiddle.skia.org/c/@Image_makeRasterImage>
1511    pub fn make_raster_image<'a>(
1512        &self,
1513        context: impl Into<Option<&'a mut gpu::DirectContext>>,
1514        caching_hint: impl Into<Option<CachingHint>>,
1515    ) -> Option<Image> {
1516        let caching_hint = caching_hint.into().unwrap_or(CachingHint::Disallow);
1517        Image::from_ptr(unsafe {
1518            sb::C_SkImage_makeRasterImage(
1519                self.native(),
1520                context.into().native_ptr_or_null_mut(),
1521                caching_hint,
1522            )
1523        })
1524    }
1525
1526    /// Creates filtered [`Image`]. filter processes original [`Image`], potentially changing
1527    /// color, position, and size. subset is the bounds of original [`Image`] processed
1528    /// by filter. `clip_bounds` is the expected bounds of the filtered [`Image`]. `out_subset`
1529    /// is required storage for the actual bounds of the filtered [`Image`]. offset is
1530    /// required storage for translation of returned [`Image`].
1531    ///
1532    /// Returns `None` if [`Image`] could not be created or if the recording context provided doesn't
1533    /// match the GPU context in which the image was created. If `None` is returned, `out_subset`
1534    /// and offset are undefined.
1535    ///
1536    /// Useful for animation of [`ImageFilter`] that varies size from frame to frame.
1537    /// Returned [`Image`] is created larger than required by filter so that GPU texture
1538    /// can be reused with different sized effects. `out_subset` describes the valid bounds
1539    /// of GPU texture returned. offset translates the returned [`Image`] to keep subsequent
1540    /// animation frames aligned with respect to each other.
1541    ///
1542    /// - `context`      the [`gpu::RecordingContext`] in play - if it exists
1543    /// - `filter`       how [`Image`] is sampled when transformed
1544    /// - `subset`       bounds of [`Image`] processed by filter
1545    /// - `clip_bounds`   expected bounds of filtered [`Image`]
1546    /// - `out_subset`    storage for returned [`Image`] bounds
1547    /// - `offset`       storage for returned [`Image`] translation
1548    ///
1549    /// Returns: filtered [`Image`], or `None`
1550    #[deprecated(since = "0.67.0", note = "use images::make_with_filter()")]
1551    pub fn new_with_filter(
1552        &self,
1553        _context: Option<&mut gpu::RecordingContext>,
1554        filter: &ImageFilter,
1555        clip_bounds: impl Into<IRect>,
1556        subset: impl Into<IRect>,
1557    ) -> Option<(Image, IRect, IPoint)> {
1558        images::make_with_filter(self, filter, subset.into(), clip_bounds.into())
1559    }
1560
1561    // TODO: MakeBackendTextureFromSkImage()
1562
1563    /// Returns `true` if [`Image`] is backed by an image-generator or other service that creates
1564    /// and caches its pixels or texture on-demand.
1565    ///
1566    /// Returns: `true` if [`Image`] is created as needed
1567    ///
1568    /// example: <https://fiddle.skia.org/c/@Image_isLazyGenerated_a>
1569    /// example: <https://fiddle.skia.org/c/@Image_isLazyGenerated_b>
1570    pub fn is_lazy_generated(&self) -> bool {
1571        unsafe { sb::C_SkImage_isLazyGenerated(self.native()) }
1572    }
1573
1574    /// See [`Self::new_color_space_with_context`]
1575    #[deprecated(since = "0.64.0", note = "use make_color_space()")]
1576    pub fn new_color_space(&self, color_space: impl Into<Option<ColorSpace>>) -> Option<Image> {
1577        self.make_color_space(None, color_space)
1578    }
1579
1580    /// Creates [`Image`] in target [`ColorSpace`].
1581    /// Returns `None` if [`Image`] could not be created.
1582    ///
1583    /// Returns original [`Image`] if it is in target [`ColorSpace`].
1584    /// Otherwise, converts pixels from [`Image`] [`ColorSpace`] to target [`ColorSpace`].
1585    /// If [`Image`] `color_space()` returns `None`, [`Image`] [`ColorSpace`] is assumed to be `s_rgb`.
1586    ///
1587    /// If this image is texture-backed, the context parameter is required and must match the
1588    /// context of the source image.
1589    ///
1590    /// - `target`   [`ColorSpace`] describing color range of returned [`Image`]
1591    /// - `direct`   The [`gpu::DirectContext`] in play, if it exists
1592    ///
1593    /// Returns: created [`Image`] in target [`ColorSpace`]
1594    ///
1595    /// example: <https://fiddle.skia.org/c/@Image_makeColorSpace>
1596    #[deprecated(since = "0.64.0", note = "use make_color_space()")]
1597    pub fn new_color_space_with_context<'a>(
1598        &self,
1599        color_space: impl Into<Option<ColorSpace>>,
1600        direct: impl Into<Option<&'a mut gpu::DirectContext>>,
1601    ) -> Option<Image> {
1602        self.make_color_space(direct, color_space)
1603    }
1604
1605    /// Creates [`Image`] in target [`ColorSpace`].
1606    /// Returns `None` if [`Image`] could not be created.
1607    ///
1608    /// Returns original [`Image`] if it is in target [`ColorSpace`].
1609    /// Otherwise, converts pixels from [`Image`] [`ColorSpace`] to target [`ColorSpace`].
1610    /// If [`Image`] `color_space()` returns `None`, [`Image`] [`ColorSpace`] is assumed to be `s_rgb`.
1611    ///
1612    /// If this image is texture-backed, the context parameter is required and must match the
1613    /// context of the source image.
1614    ///
1615    /// - `direct`   The [`gpu::DirectContext`] in play, if it exists
1616    /// - `target`   [`ColorSpace`] describing color range of returned [`Image`]
1617    ///
1618    /// Returns: created [`Image`] in target [`ColorSpace`]
1619    ///
1620    /// example: <https://fiddle.skia.org/c/@Image_makeColorSpace>
1621    pub fn make_color_space<'a>(
1622        &self,
1623        direct: impl Into<Option<&'a mut gpu::DirectContext>>,
1624        color_space: impl Into<Option<ColorSpace>>,
1625    ) -> Option<Image> {
1626        Image::from_ptr(unsafe {
1627            sb::C_SkImage_makeColorSpace(
1628                self.native(),
1629                direct.into().native_ptr_or_null_mut(),
1630                color_space.into().into_ptr_or_null(),
1631            )
1632        })
1633    }
1634
1635    /// Creates a new [`Image`] identical to this one, but with a different [`ColorSpace`].
1636    /// This does not convert the underlying pixel data, so the resulting image will draw
1637    /// differently.
1638    pub fn reinterpret_color_space(&self, new_color_space: impl Into<ColorSpace>) -> Option<Image> {
1639        Image::from_ptr(unsafe {
1640            sb::C_SkImage_reinterpretColorSpace(self.native(), new_color_space.into().into_ptr())
1641        })
1642    }
1643}