Skiasharp: missing SKImageEncoder (want to store SKBitmap to stream)

Created on 28 Jun 2016  路  7Comments  路  Source: mono/SkiaSharp

Hi!

I am currently developing an SVG editor for Android (but very likely also for iOS, UWP, etc.)
My problem now is, that I would like to store an SKBitmap to a file as PNG.
I saw that there is a SKImageEncoder which does the job, but it is not mapped yet.
Any chances this will change in the near future? (I do not like workarounds)

https://github.com/google/skia/blob/master/src/images/SkImageEncoder.cpp

All 7 comments

If you have an SKBitmap, you can call:

var data = bitmap.Encode (SKImageEncodeFormat.Png, quality: 100);
using (var f = File.Create ("foo.png"))
   data.SaveTo (f);

Unfortunately this is not true:
SKBitmap (at last in version 1.49.4-beta) does not have a method "Encode" :-|

see here: https://github.com/mono/SkiaSharp/blob/master/binding/Binding/SKBitmap.cs

AAAH! Now I think I see what the problem is!
You meant "SKImage" but wrote "SKBitmap", right? Because SKImage has an "Encode" method :)
So if I have some "SKBitmap" that I'd like to store, I'd do the following (please correct me if I'm wrong):
`

        SKBitmap bitmap = ... I get it from somewhere - trust me;
        using(var img = SKImage.FromPixels(bitmap.Info, bitmap.Handle, si.Width * 4))
        {
            var data = img.Encode(SKImageEncodeFormat.Png, quality: 100);
            data.SaveTo(stream);
        }

`

... no... that was definetly wrong.... but I guess I am on the right track...

I always get a SIGSEGV so I am doing something wrong, although it seems correct to me:

    SKBitmap bitmap = Image;
    try
    {
        bitmap.LockPixels();
        IntPtr p;
        bitmap.GetPixels(out p);
        using (var img = SKImage.FromPixels(bitmap.Info, bitmap.Handle, bitmap.Width * bitmap.BytesPerPixel))
        {
            var data = img.Encode(SKImageEncodeFormat.Png, quality: quality);
            data.SaveTo(stream);
        }
    }
    finally
    {
        bitmap.UnlockPixels();
    }

the stacktrace is:4

06-29 14:34:24.051 E/mono-rt (31174): Stacktrace:
06-29 14:34:24.051 E/mono-rt (31174):
06-29 14:34:24.051 E/mono-rt (31174): at <0xffffffff>
06-29 14:34:24.051 E/mono-rt (31174): at (wrapper managed-to-native) SkiaSharp.SkiaApi.sk_image_new_raster_copy (SkiaSharp.SKImageInfo&,intptr,intptr)
06-29 14:34:24.051 E/mono-rt (31174): at SkiaSharp.SKImage.FromPixels (SkiaSharp.SKImageInfo,intptr,int)
06-29 14:34:24.051 E/mono-rt (31174): at Svg.Platform.SkiaBitmap.SavePng (System.IO.Stream,int) [0x00019] in C:CodeiclSVGSVGSvg.CorePlatformSkiaBitmap.cs:66
06-29 14:34:24.051 E/mono-rt (31174): at Svg.Droid.SampleEditor.Core.Tools.SaveTool/<>c__DisplayClass3_0.b__8 (object) [0x0006d] in C:CodeiclSVGSVGSvg.Editor.Sample.CoreToolsSaveTool.cs:138
06-29 14:34:24.051 E/mono-rt (31174): at Svg.Core.Tools.ToolCommand.Execute (object) [0x00001] in C:CodeiclSVGSVGSvg.Editor.CoreToolsITool.cs:97
06-29 14:34:24.051 E/mono-rt (31174): at Svg.Droid.SampleEditor.Views.EditorView.OnOptionsItemSelected (Android.Views.IMenuItem) [0x0005d] in C:CodeiclSVGSVGSvg.Editor.Sample.DroidViewsEditorView.cs:126
06-29 14:34:24.051 E/mono-rt (31174): at Android.App.Activity.n_OnOptionsItemSelected_Landroid_view_MenuItem_ (intptr,intptr,intptr) [0x00011] in /Users/builder/data/lanes/3236/ee215fc9/source/monodroid/src/Mono.Android/platforms/android-23/src/generated/Android.App.Activity.cs:3935
06-29 14:34:24.051 E/mono-rt (31174): at (wrapper dynamic-method) object.7c4f615e-b4f8-41e0-a9ab-ecd5399d7c82 (intptr,intptr,intptr)
06-29 14:34:24.051 E/mono-rt (31174): at (wrapper native-to-managed) object.7c4f615e-b4f8-41e0-a9ab-ecd5399d7c82 (intptr,intptr,intptr)
06-29 14:34:24.051 E/mono-rt (31174):
06-29 14:34:24.051 E/mono-rt (31174): Attempting native Android stacktrace:
06-29 14:34:24.051 E/mono-rt (31174):
06-29 14:34:24.066 E/mono-rt (31174): at __memcpy_base+88 [0x400d726c]
06-29 14:34:24.066 E/mono-rt (31174): at SkData::PrivateNewWithCopy(void const*, unsigned int)+36 [0x847185e5]
06-29 14:34:24.066 E/mono-rt (31174):
06-29 14:34:24.066 E/mono-rt (31174): =================================================================
06-29 14:34:24.066 E/mono-rt (31174): Got a SIGSEGV while executing native code. This usually indicates
06-29 14:34:24.066 E/mono-rt (31174): a fatal error in the mono runtime or one of the native libraries
06-29 14:34:24.066 E/mono-rt (31174): used by your application.
06-29 14:34:24.066 E/mono-rt (31174): =================================================================
06-29 14:34:24.066 E/mono-rt (31174):
06-29 14:34:24.066 F/libc (31174): Fatal signal 11 (SIGSEGV) at 0x00019000 (code=1), thread 31174 (id.SampleEditor)

I just saw, that there is conversion function in SKIA - could that be bound in SkiaSharp?

static sk_sp<SkImage> MakeFromBitmap(const SkBitmap&);

see SKImage.h
https://github.com/google/skia/blob/master/include/core/SkImage.h

... but if I look at the implementation, I would assume that my second implementation is correct - but still it is failing...

see: SKImage.cpp
https://github.com/google/skia/blob/master/src/image/SkImage.cpp

sk_sp<SkImage> SkImage::MakeFromBitmap(const SkBitmap& bm) { SkPixelRef* pr = bm.pixelRef(); if (nullptr == pr) { return nullptr; }

@gentledepp Is this still an issue?

I am thinking that you are passing the wrong IntPtr to SKImage.FromPixels:

    SKBitmap bitmap = Image;
    try
    {
        bitmap.LockPixels();
        IntPtr p;
        IntPtr pixels = bitmap.GetPixels(out p); // this line and the next
        using (var img = SKImage.FromPixels(bitmap.Info, pixels, bitmap.Width * bitmap.BytesPerPixel))
        {
            var data = img.Encode(SKImageEncodeFormat.Png, quality: quality);
            data.SaveTo(stream);
        }
    }
    finally
    {
        bitmap.UnlockPixels();
    }

You should never have to reference the object.Handle from outside the SkiaSharp library. If you have to, you can never know what the underlying native type will be.

Was this page helpful?
0 / 5 - 0 ratings