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}