Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Png chunk reader codec bitmap #2149

Open
wants to merge 39 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
504a32e
add /.idea to git ignore
mgood7123 Jul 1, 2022
c418306
Merge pull request #2 from mono/main
mgood7123 Jul 3, 2022
7b9a53e
Merge branch 'mono:main' into main
mgood7123 Jul 7, 2022
de972eb
add SKPngChunkReader
mgood7123 Jul 7, 2022
bcf7b54
add SKPngChunkReader bindings
mgood7123 Jul 7, 2022
f7600da
add renamed SKPngChunkReader bindings
mgood7123 Jul 7, 2022
155a87a
expose more of SKCodec
mgood7123 Jul 7, 2022
996d8cf
expose more SKCodec bindings
mgood7123 Jul 7, 2022
2285f86
expose more of SKBitmap
mgood7123 Jul 7, 2022
bd7ee47
expose more SKBitmap bindings
mgood7123 Jul 7, 2022
4c198f6
remove api meant for other PR
mgood7123 Jul 7, 2022
c5cd679
add cpp files to tizen
mgood7123 Jul 7, 2022
afc7a9f
add json changes
mgood7123 Jul 8, 2022
0c000d4
rename to match
mgood7123 Jul 8, 2022
1fc7c6e
rename to match
mgood7123 Jul 8, 2022
c618eec
rename to match
mgood7123 Jul 9, 2022
3a55937
fix bindings json
mgood7123 Jul 9, 2022
5c3586b
fix params
mgood7123 Jul 9, 2022
dca69e2
fix bindings
mgood7123 Jul 9, 2022
5dfbf18
SKCodec.SelectionPolicy -> SKCodecSelectionPolicy
mgood7123 Jul 9, 2022
4307413
fix enum
mgood7123 Jul 9, 2022
cf7eee8
regenerate bindings
mgood7123 Jul 9, 2022
0c9f33b
fix enum
mgood7123 Jul 9, 2022
c134ffb
fix C# binding callbacks
mgood7123 Jul 9, 2022
334b7c3
fix incorrect member name
mgood7123 Jul 9, 2022
e8bdd75
remove comments, cleanup ReadChunk api
mgood7123 Jul 12, 2022
b362f1a
removed needlessly overriden Dispose
mgood7123 Jul 12, 2022
368b72e
Merge branch 'main' into png_chunk_reader_codec_bitmap
mgood7123 Jul 12, 2022
052ee1c
fix abstract ReadChunk having method body
mgood7123 Aug 6, 2022
b12d3e2
Merge remote-tracking branch 'origin/png_chunk_reader_codec_bitmap' i…
mgood7123 Aug 6, 2022
0325714
Merge branch 'main' into png_chunk_reader_codec_bitmap
mattleibow Aug 8, 2022
b71e029
Merge branch 'main' into pr/2149
mattleibow Aug 14, 2022
6077608
Run code formatter
mattleibow Aug 14, 2022
09a7d2b
reduce overloads
mattleibow Aug 14, 2022
80b5fd1
Adding some tests
mattleibow Aug 15, 2022
44a5ecc
Update SKPngChunkReader.cs
mgood7123 Aug 21, 2022
64241d9
modify for Non Standard chunk
mgood7123 Aug 26, 2022
b6ad3dd
Add files via upload
mgood7123 Aug 26, 2022
ff367a2
Update SKCodecTest.cs
mgood7123 Aug 26, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 78 additions & 2 deletions binding/Binding/SKBitmap.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,6 @@ public static SKFilterQuality ToFilterQuality (this SKBitmapResizeMethod method)
}

// TODO: keep in mind SKBitmap may be going away (according to Google)
// TODO: `ComputeIsOpaque` may be useful
// TODO: `GenerationID` may be useful
// TODO: `GetAddr` and `GetPixel` are confusing

public unsafe class SKBitmap : SKObject, ISKSkipObjectRegistration
Expand Down Expand Up @@ -115,6 +113,47 @@ protected override void Dispose (bool disposing) =>
protected override void DisposeNative () =>
SkiaApi.sk_bitmap_destructor (Handle);

// Other

public bool SetInfo (SKImageInfo info) =>
SetInfo (info, 0);

public bool SetInfo (SKImageInfo info, int rowBytes)
{
var cinfo = SKImageInfoNative.FromManaged (ref info);
return SkiaApi.sk_bitmap_set_info (Handle, &cinfo, (IntPtr)rowBytes);
}

public bool ComputeIsOpaque () =>
SkiaApi.sk_bitmap_compute_is_opaque (Handle);

// AllocPixels

public void AllocPixels (SKImageInfo info) =>
AllocPixels (info, info.RowBytes);

public void AllocPixels (SKImageInfo info, int rowBytes)
{
if (!TryAllocPixels (info, rowBytes)) {
SKImageInfo i = Info;
throw new OutOfMemoryException ("SkBitmap::tryAllocPixels failed "
+ "ColorType:" + i.ColorType + "AlphaType:" + i.AlphaType +
"[w:" + i.Width + " h:" + i.Height + "] rb:" + RowBytes
);
}
}

public void AllocPixels (SKImageInfo info, SKBitmapAllocFlags flags)
{
if (!TryAllocPixels (info, flags)) {
SKImageInfo i = Info;
throw new OutOfMemoryException ("SkBitmap::tryAllocPixels failed "
+ "ColorType:" + i.ColorType + "AlphaType:" + i.AlphaType +
"[w:" + i.Width + " h:" + i.Height + "] rb:" + RowBytes
);
}
}

// TryAllocPixels

public bool TryAllocPixels (SKImageInfo info)
Expand Down Expand Up @@ -361,6 +400,9 @@ public int ByteCount {
get { return (int)SkiaApi.sk_bitmap_get_byte_count (Handle); }
}

public uint GenerationId =>
(uint)SkiaApi.sk_bitmap_get_generation_id (Handle);

// *Pixels*

public IntPtr GetPixels () =>
Expand Down Expand Up @@ -401,6 +443,14 @@ public void SetColorTable (SKColorTable ct)

// more properties

public SKPixmap Pixmap {
get {
var pixmap = new SKPixmap (SkiaApi.sk_bitmap_get_pixmap (Handle), false); // pixmap is owned by this
pixmap.pixelSource = this;
return pixmap;
}
}
mgood7123 marked this conversation as resolved.
Show resolved Hide resolved

public byte[] Bytes {
get {
var array = GetPixelSpan ().ToArray ();
Expand Down Expand Up @@ -723,6 +773,29 @@ public bool InstallPixels (SKImageInfo info, IntPtr pixels, int rowBytes, SKBitm
return SkiaApi.sk_bitmap_install_pixels (Handle, &cinfo, (void*)pixels, (IntPtr)rowBytes, proxy, (void*)ctx);
}

public bool ReadPixels (SKImageInfo info, IntPtr dstPixels, int rowBytes, int x, int y)
{
if (GetPixels () == IntPtr.Zero)
return false;
return Pixmap.ReadPixels (info, dstPixels, rowBytes, x, y);
}

public bool ReadPixels (SKPixmap dstPixmap) =>
ReadPixels (dstPixmap, 0, 0);

public bool ReadPixels (SKPixmap dstPixmap, int x, int y)
{
if (GetPixels () == IntPtr.Zero)
return false;
return Pixmap.ReadPixels (dstPixmap.Info, dstPixmap.GetPixels (), dstPixmap.RowBytes, x, y);
}

public bool WritePixels (SKPixmap pixmap) =>
WritePixels (pixmap, 0, 0);

public bool WritePixels (SKPixmap dstPixmap, int x, int y) =>
SkiaApi.sk_bitmap_write_pixels_at_location (Handle, dstPixmap.Handle, x, y);

public bool InstallPixels (SKPixmap pixmap)
{
return SkiaApi.sk_bitmap_install_pixels_with_pixmap (Handle, pixmap.Handle);
Expand Down Expand Up @@ -842,6 +915,9 @@ public static SKBitmap FromImage (SKImage image)
return bmp;
}

public SKImage ToImage () =>
SKImage.FromBitmap (this);

// Encode

public SKData Encode (SKEncodedImageFormat format, int quality)
Expand Down
46 changes: 33 additions & 13 deletions binding/Binding/SKCodec.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

namespace SkiaSharp
{
// TODO: `Create(...)` should have overloads that accept a SKPngChunkReader
// TODO: missing the `QueryYuv8` and `GetYuv8Planes` members

public unsafe class SKCodec : SKObject, ISKSkipObjectRegistration
Expand Down Expand Up @@ -42,6 +41,8 @@ public SKImageInfo Info {
public SKEncodedImageFormat EncodedFormat =>
SkiaApi.sk_codec_get_encoded_format (Handle);

public SKSizeI EncodedDimensions => Info.Size;

public SKSizeI GetScaledDimensions (float desiredScale)
{
SKSizeI dimensions;
Expand Down Expand Up @@ -277,53 +278,72 @@ public bool SkipScanlines (int countLines) =>
public int GetOutputScanline (int inputScanline) =>
SkiaApi.sk_codec_output_scanline (Handle, inputScanline);

// create (streams)
// create (filename)

public static SKCodec Create (string filename) =>
Create (filename, out var result);
Create (filename, null, SKCodecSelectionPolicy.PreferStillImage, out _);

public static SKCodec Create (string filename, out SKCodecResult result) =>
Create (filename, null, SKCodecSelectionPolicy.PreferStillImage, out result);

public static SKCodec Create (string filename, out SKCodecResult result)
public static SKCodec Create (string filename, SKPngChunkReader chunkReader, SKCodecSelectionPolicy selectionPolicy, out SKCodecResult result)
{
var stream = SKFileStream.OpenStream (filename);
if (stream == null) {
result = SKCodecResult.InternalError;
return null;
}

return Create (stream, out result);
return Create (stream, chunkReader, selectionPolicy, out result);
}

// create (Stream)

public static SKCodec Create (Stream stream) =>
Create (stream, out var result);
Create (WrapManagedStream (stream), null, SKCodecSelectionPolicy.PreferStillImage, out _);

public static SKCodec Create (Stream stream, out SKCodecResult result) =>
Create (WrapManagedStream (stream), out result);
Create (WrapManagedStream (stream), null, SKCodecSelectionPolicy.PreferStillImage, out result);

public static SKCodec Create (Stream stream, SKPngChunkReader chunkReader, SKCodecSelectionPolicy selectionPolicy, out SKCodecResult result) =>
Create (WrapManagedStream (stream), chunkReader, selectionPolicy, out result);

// create (SKStream)

public static SKCodec Create (SKStream stream) =>
Create (stream, out var result);
Create (stream, null, SKCodecSelectionPolicy.PreferStillImage, out _);

public static SKCodec Create (SKStream stream, out SKCodecResult result) =>
Create (stream, null, SKCodecSelectionPolicy.PreferStillImage, out result);

public static SKCodec Create (SKStream stream, out SKCodecResult result)
public static SKCodec Create (SKStream stream, SKPngChunkReader chunkReader, SKCodecSelectionPolicy selectionPolicy, out SKCodecResult result)
{
if (stream == null)
throw new ArgumentNullException (nameof (stream));
if (stream is SKFileStream filestream && !filestream.IsValid)
throw new ArgumentException ("File stream was not valid.", nameof(stream));
throw new ArgumentException ("File stream was not valid.", nameof (stream));

fixed (SKCodecResult* r = &result) {
var codec = GetObject (SkiaApi.sk_codec_new_from_stream (stream.Handle, r));
var codec = GetObject (SkiaApi.sk_codec_new_from_stream_with_pngchunkreader_and_selection_policy (stream.Handle, r, chunkReader?.Handle ?? IntPtr.Zero, selectionPolicy));
stream.RevokeOwnership (codec);
Referenced (codec, chunkReader);
return codec;
}
}

// create (data)

public static SKCodec Create (SKData data)
public static SKCodec Create (SKData data) =>
Create (data, null);

public static SKCodec Create (SKData data, SKPngChunkReader chunkReader)
{
if (data == null)
throw new ArgumentNullException (nameof (data));

return GetObject (SkiaApi.sk_codec_new_from_data (data.Handle));
var codec = GetObject (SkiaApi.sk_codec_new_from_data_with_pngchunkreader (data.Handle, chunkReader?.Handle ?? IntPtr.Zero));
Referenced (codec, chunkReader);
return codec;
}

// utils
Expand Down
2 changes: 1 addition & 1 deletion binding/Binding/SKObject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ internal static T Owned<T> (T owner, SKObject child)
return owner;
}

// indicate that the chile should not be garbage collected while
// indicate that the child should not be garbage collected while
// the owner still lives
internal static T Referenced<T> (T owner, SKObject child)
where T : SKObject
Expand Down
62 changes: 62 additions & 0 deletions binding/Binding/SKPngChunkReader.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
using System;
using System.Runtime.InteropServices;
using System.Threading;

namespace SkiaSharp
{
public unsafe abstract class SKPngChunkReader : SKObject, ISKSkipObjectRegistration
{
private static readonly SKManagedPngChunkReaderDelegates delegates;
private readonly IntPtr userData;
private int fromNative;

static SKPngChunkReader ()
{
delegates = new SKManagedPngChunkReaderDelegates {
fReadChunk = ReadChunkInternal,
fDestroy = DestroyInternal,
};

SkiaApi.sk_managedpngchunkreader_set_procs (delegates);
}

protected SKPngChunkReader ()
: base (IntPtr.Zero, true)
{
userData = DelegateProxies.CreateUserData (this, true);
Handle = SkiaApi.sk_managedpngchunkreader_new ((void*)userData);

if (Handle == IntPtr.Zero)
throw new InvalidOperationException ("Unable to create a new SKPngChunkReader instance.");
}

protected override void DisposeNative ()
{
if (Interlocked.CompareExchange (ref fromNative, 0, 0) == 0) {
SkiaApi.sk_managedpngchunkreader_delete (Handle);
}
}

protected abstract bool ReadChunk (string tag, IntPtr data, IntPtr length);

// impl

[MonoPInvokeCallback (typeof (SKManagedPngChunkReaderReadChunkProxyDelegate))]
private static bool ReadChunkInternal (IntPtr d, void* context, void* tag, void* data, IntPtr length)
{
var dump = DelegateProxies.GetUserData<SKPngChunkReader> ((IntPtr)context, out _);
return dump.ReadChunk (Marshal.PtrToStringAnsi ((IntPtr)tag), (IntPtr)data, length);
}

[MonoPInvokeCallback (typeof (SKManagedPngChunkReaderDestroyProxyDelegate))]
private static void DestroyInternal (IntPtr s, void* context)
{
var id = DelegateProxies.GetUserData<SKPngChunkReader> ((IntPtr)context, out var gch);
if (id != null) {
Interlocked.Exchange (ref id.fromNative, 1);
id.Dispose ();
}
gch.Free ();
}
}
}
Loading