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