Sample how to use scalePixels()?

72 views
Skip to first unread message

Stefan O.

unread,
Mar 21, 2024, 11:49:02 AMMar 21
to skia-discuss
Is there a full sample how to use SkImage.scalePixels()?

Today I use the drawImageRect() method which gives me rather blocky images.
I want to try how the result of scalePixels() looks like and if it's faster or consumes less memory.

scalePixels() wants a Pixmap, but I don't know how to create that from an Image I have.

See also https://github.com/JetBrains/skiko/issues/626


Brian Osman

unread,
Mar 21, 2024, 2:58:06 PMMar 21
to skia-d...@googlegroups.com
I'm not sure what's exposed in skiko, but in native Skia, you can control the filtering quality when doing the drawImageRect with the SkSamplingOptions parameter (to enable linear or cubic filtering). The overall quality and performance of the two techniques should be the same (scalePixels is implemented internally by doing a rect-to-rect draw: https://crsrc.org/c/third_party/skia/src/core/SkPixmapDraw.cpp;drc=5c93acf313d1cf72f8b73886168bd925b5011b8c;l=84


--
You received this message because you are subscribed to the Google Groups "skia-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to skia-discuss...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/skia-discuss/0e6a4cd1-b8ef-4f4d-941c-b068de848adan%40googlegroups.com.

Stefan O.

unread,
Mar 21, 2024, 4:32:02 PMMar 21
to skia-discuss
Thank you for letting me know. So it does the same internally and might have the same results.

Skiko exposes the SkSamplingOptions, but I found that they all do not look good on downsampling.
Even with anti aliasing enabled.

Maybe there is more to creating good thumbnails, I'm not sure.

Stefan O.

unread,
Mar 22, 2024, 6:08:35 AMMar 22
to skia-discuss
I guess there might be a problem with the skiko binding.
Setting anti alias paint has no effect: https://github.com/JetBrains/skiko/issues/896

Is this a bug in the binding or is it the wrong way to enable anti alias?

Brian Osman

unread,
Mar 22, 2024, 9:12:41 AMMar 22
to skia-d...@googlegroups.com
Actually, that's working correctly - antialias won't have any impact on image rescaling. There are two similar (but different) concepts here: antialiasing is just about the geometry (coverage) - it creates smooth edges to whatever shape is being drawn. Antialiasing never impacts the interior of shapes, nor does it impact the SkShader (essentially the fill-pattern for the shape). In the case of a drawImage call, the shape is implicitly a rectangle, and the SkShader is implicitly the image. Filtering (SkSamplingOptions/SkFilterMode) is about how the contents of an image are sampled, even on the interior of a shape. So I'd only expect different results from the different SkFilterMode values. If you have a result that doesn't look good, could you post an example to fiddle.skia.org?

Stefan O.

unread,
Mar 22, 2024, 9:51:59 AMMar 22
to skia-discuss
Thanks, that explains a lot.

The different SkSamplingOptions yield different results, but all of them look blocky (at the hairs) compared with GIMP.

I scaled down the same image using LINEAR scaling in GIMP and Skia. GIMP looks much better.
I suspect this is due to the anti aliasing. The linear scaling algorithm should be the same logic in both, or not?

gimp_vs_skia.png

This is the Kotlin code using skiko:

fun Image.scaleToThumbnail(): Image {

  val surface = Surface.makeRasterN32Premul(480, 320)

  surface.canvas.drawImageRect(
   image = this,
   src = Rect.makeWH(width.toFloat(), height.toFloat()),
   dst = Rect.makeWH(480f, 320f),
   samplingMode = SamplingMode.LINEAR,
   paint = Paint().apply { isAntiAlias = true }, // no effect
   strict = true
  )

  return surface.makeImageSnapshot()
}

I think I can't upload custom images on SKIA fiddle.

Brian Osman

unread,
Mar 22, 2024, 9:56:56 AMMar 22
to skia-d...@googlegroups.com
That definitely looks worse than I'd expect. How large is the source image? If it's more than 2x larger than your destination, try specifying MipmapMode (looks like you can specify that for your SamplingOptions?). That should improve the down-scaling quality quite a bit.

Stefan O.

unread,
Mar 22, 2024, 10:08:09 AMMar 22
to skia-discuss
Unfortunately changing that results in the same image.

samplingMode = FilterMipmap(FilterMode.LINEAR, MipmapMode.NONE)
and
samplingMode = FilterMipmap(FilterMode.LINEAR, MipmapMode.LINEAR)
don't make a difference.

The original image is 2000x1333, so much larger.


It claims that SKIA can't downsize more than 50% at once while preversing quality.
Multiple iterations are recommended.

If it's really not a anti aliasing problem I guess I should file an issue wishing for a better scaling algorithm.

Stefan O.

unread,
Mar 22, 2024, 10:37:03 AMMar 22
to skia-discuss
Ok, it's true. Downscaling multiple times by factor two looks way better than doing this one-shot. It's not an AA issue.

Scaling down multiple times costs more memory and time. I'm not too happy here.

multi_vs_oneshot.png

Stefan O.

unread,
Mar 22, 2024, 11:04:24 AMMar 22
to skia-discuss
https://issues.skia.org/issues/40043842#comment2 ...

May that be true, that GIMP also performs multiple downscaling operations?

Can't we automate such a thing in SKIA?

I still don't understand why the MipmapMode does not have any effect.

John Stiles

unread,
Mar 22, 2024, 11:15:50 AMMar 22
to skia-d...@googlegroups.com
Are you actually setting up mipmaps when creating the SkImage? 

You can get similar results using mipmaps, since that effectively stores the progressively downsampled images, but this should be specified at creation time of the SkImage. Just switching the mipmap mode to linear will not necessarily trigger the generation of mipmaps.


Stefan O.

unread,
Mar 22, 2024, 11:21:52 AMMar 22
to skia-discuss
Hard to tell what skiko does behind the scenes.

But I just found out that on calling scalePixels() the MipmapMode is respected, while on drawImageInRect() it's ignored.

Using skiko this is code that yields a good result:

val bitmap = Bitmap()
bitmap.allocN32Pixels(thumbnailSize.width, thumbnailSize.height)
this.scalePixels(bitmap.peekPixels()!!, FilterMipmap(FilterMode.LINEAR, MipmapMode.LINEAR), false)
Image.makeFromBitmap(bitmap)

I will file a ticket to the skiko team.

Consider this solved. Thank you all for teaching me.
Reply all
Reply to author
Forward
0 new messages