diff --git a/binding/SkiaSharp.Resources/ResourcesApi.generated.cs b/binding/SkiaSharp.Resources/ResourcesApi.generated.cs index 7a98213520..9a120d354e 100644 --- a/binding/SkiaSharp.Resources/ResourcesApi.generated.cs +++ b/binding/SkiaSharp.Resources/ResourcesApi.generated.cs @@ -51,6 +51,8 @@ using sk_path_rawiterator_t = System.IntPtr; using sk_path_t = System.IntPtr; using sk_pathmeasure_t = System.IntPtr; +using sk_pdf_metadata_t = System.IntPtr; +using sk_pdf_structure_element_t = System.IntPtr; using sk_picture_recorder_t = System.IntPtr; using sk_picture_t = System.IntPtr; using sk_pixelref_factory_t = System.IntPtr; diff --git a/binding/SkiaSharp.SceneGraph/SceneGraphApi.generated.cs b/binding/SkiaSharp.SceneGraph/SceneGraphApi.generated.cs index 6ddb553ba7..c3475dd133 100644 --- a/binding/SkiaSharp.SceneGraph/SceneGraphApi.generated.cs +++ b/binding/SkiaSharp.SceneGraph/SceneGraphApi.generated.cs @@ -51,6 +51,8 @@ using sk_path_rawiterator_t = System.IntPtr; using sk_path_t = System.IntPtr; using sk_pathmeasure_t = System.IntPtr; +using sk_pdf_metadata_t = System.IntPtr; +using sk_pdf_structure_element_t = System.IntPtr; using sk_picture_recorder_t = System.IntPtr; using sk_picture_t = System.IntPtr; using sk_pixelref_factory_t = System.IntPtr; diff --git a/binding/SkiaSharp.Skottie/SkottieApi.generated.cs b/binding/SkiaSharp.Skottie/SkottieApi.generated.cs index 548ed1a044..47f994cce2 100644 --- a/binding/SkiaSharp.Skottie/SkottieApi.generated.cs +++ b/binding/SkiaSharp.Skottie/SkottieApi.generated.cs @@ -51,6 +51,8 @@ using sk_path_rawiterator_t = System.IntPtr; using sk_path_t = System.IntPtr; using sk_pathmeasure_t = System.IntPtr; +using sk_pdf_metadata_t = System.IntPtr; +using sk_pdf_structure_element_t = System.IntPtr; using sk_picture_recorder_t = System.IntPtr; using sk_picture_t = System.IntPtr; using sk_pixelref_factory_t = System.IntPtr; diff --git a/binding/SkiaSharp/SKBitmap.cs b/binding/SkiaSharp/SKBitmap.cs index 93219f0b90..72b65433bd 100644 --- a/binding/SkiaSharp/SKBitmap.cs +++ b/binding/SkiaSharp/SKBitmap.cs @@ -783,5 +783,10 @@ public SKShader ToShader (SKShaderTileMode tmx, SKShaderTileMode tmy, SKFilterQu private SKShader ToShader (SKShaderTileMode tmx, SKShaderTileMode tmy, SKSamplingOptions sampling, SKMatrix* localMatrix) => SKShader.GetObject (SkiaApi.sk_bitmap_make_shader (Handle, tmx, tmy, &sampling, localMatrix)); + + // ToImage + + public SKImage ToImage () => + SKImage.FromBitmap (this); } } diff --git a/binding/SkiaSharp/SKDocument.cs b/binding/SkiaSharp/SKDocument.cs index 2330964be8..5f058edf56 100644 --- a/binding/SkiaSharp/SKDocument.cs +++ b/binding/SkiaSharp/SKDocument.cs @@ -1,178 +1,308 @@ -#nullable disable - -using System; -using System.ComponentModel; +using System; +using System.Collections.Generic; using System.IO; +using System.Runtime.InteropServices; + +namespace SkiaSharp; -namespace SkiaSharp +public unsafe class SKDocument : SKObject, ISKReferenceCounted, ISKSkipObjectRegistration { - public unsafe class SKDocument : SKObject, ISKReferenceCounted, ISKSkipObjectRegistration + public const float DefaultRasterDpi = 72.0f; + + internal SKDocument (IntPtr handle, bool owns) + : base (handle, owns) { - public const float DefaultRasterDpi = 72.0f; + } - internal SKDocument (IntPtr handle, bool owns) - : base (handle, owns) - { - } + protected override void Dispose (bool disposing) => + base.Dispose (disposing); - protected override void Dispose (bool disposing) => - base.Dispose (disposing); + public void Abort () => + SkiaApi.sk_document_abort (Handle); - public void Abort () => - SkiaApi.sk_document_abort (Handle); + public SKCanvas BeginPage (float width, float height) => + OwnedBy (SKCanvas.GetObject (SkiaApi.sk_document_begin_page (Handle, width, height, null), false), this); - public SKCanvas BeginPage (float width, float height) => - OwnedBy (SKCanvas.GetObject (SkiaApi.sk_document_begin_page (Handle, width, height, null), false), this); + public SKCanvas BeginPage (float width, float height, SKRect content) => + OwnedBy (SKCanvas.GetObject (SkiaApi.sk_document_begin_page (Handle, width, height, &content), false), this); - public SKCanvas BeginPage (float width, float height, SKRect content) => - OwnedBy (SKCanvas.GetObject (SkiaApi.sk_document_begin_page (Handle, width, height, &content), false), this); + public void EndPage () => + SkiaApi.sk_document_end_page (Handle); - public void EndPage () => - SkiaApi.sk_document_end_page (Handle); + public void Close () => + SkiaApi.sk_document_close (Handle); - public void Close () => - SkiaApi.sk_document_close (Handle); + // CreateXps - // CreateXps + public static SKDocument? CreateXps (string path) => + CreateXps (path, DefaultRasterDpi); - public static SKDocument CreateXps (string path) => - CreateXps (path, DefaultRasterDpi); + public static SKDocument? CreateXps (Stream stream) => + CreateXps (stream, DefaultRasterDpi); - public static SKDocument CreateXps (Stream stream) => - CreateXps (stream, DefaultRasterDpi); + public static SKDocument? CreateXps (SKWStream stream) => + CreateXps (stream, DefaultRasterDpi); - public static SKDocument CreateXps (SKWStream stream) => - CreateXps (stream, DefaultRasterDpi); + public static SKDocument? CreateXps (string path, float dpi) + { + if (path == null) { + throw new ArgumentNullException (nameof (path)); + } - public static SKDocument CreateXps (string path, float dpi) - { - if (path == null) { - throw new ArgumentNullException (nameof (path)); - } + var stream = SKFileWStream.OpenStream (path); + return Owned (CreateXps (stream, dpi), stream); + } - var stream = SKFileWStream.OpenStream (path); - return Owned (CreateXps (stream, dpi), stream); + public static SKDocument? CreateXps (Stream stream, float dpi) + { + if (stream == null) { + throw new ArgumentNullException (nameof (stream)); } - public static SKDocument CreateXps (Stream stream, float dpi) - { - if (stream == null) { - throw new ArgumentNullException (nameof (stream)); - } + var managed = new SKManagedWStream (stream); + return Owned (CreateXps (managed, dpi), managed); + } - var managed = new SKManagedWStream (stream); - return Owned (CreateXps (managed, dpi), managed); + public static SKDocument? CreateXps (SKWStream stream, float dpi) + { + if (stream == null) { + throw new ArgumentNullException (nameof (stream)); } - public static SKDocument CreateXps (SKWStream stream, float dpi) - { - if (stream == null) { - throw new ArgumentNullException (nameof (stream)); - } + return Referenced (GetObject (SkiaApi.sk_document_create_xps_from_stream (stream.Handle, dpi)), stream); + } + + // CreatePdf - return Referenced (GetObject (SkiaApi.sk_document_create_xps_from_stream (stream.Handle, dpi)), stream); + public static SKDocument CreatePdf (string path) + { + if (path == null) { + throw new ArgumentNullException (nameof (path)); } - // CreatePdf + var stream = SKFileWStream.OpenStream (path); + return Owned (CreatePdf (stream), stream); + } - public static SKDocument CreatePdf (string path) - { - if (path == null) { - throw new ArgumentNullException (nameof (path)); - } + public static SKDocument CreatePdf (Stream stream) + { + if (stream == null) { + throw new ArgumentNullException (nameof (stream)); + } + + var managed = new SKManagedWStream (stream); + return Owned (CreatePdf (managed), managed); + } - var stream = SKFileWStream.OpenStream (path); - return Owned (CreatePdf (stream), stream); + public static SKDocument CreatePdf (SKWStream stream) + { + if (stream == null) { + throw new ArgumentNullException (nameof (stream)); } - public static SKDocument CreatePdf (Stream stream) - { - if (stream == null) { - throw new ArgumentNullException (nameof (stream)); - } + return Referenced (GetObject (SkiaApi.sk_document_create_pdf_from_stream (stream.Handle)), stream); + } + + public static SKDocument CreatePdf (string path, float dpi) => + CreatePdf (path, new SKPdfMetadata { RasterDpi = dpi }); + + public static SKDocument CreatePdf (Stream stream, float dpi) => + CreatePdf (stream, new SKPdfMetadata { RasterDpi = dpi }); + + public static SKDocument CreatePdf (SKWStream stream, float dpi) => + CreatePdf (stream, new SKPdfMetadata { RasterDpi = dpi }); - var managed = new SKManagedWStream (stream); - return Owned (CreatePdf (managed), managed); + [Obsolete ("Use CreatePdf(string, SKPdfMetadata) instead.")] + public static SKDocument CreatePdf (string path, SKDocumentPdfMetadata metadata) => + CreatePdf (path, new SKPdfMetadata (metadata)); + + [Obsolete ("Use CreatePdf(Stream, SKPdfMetadata) instead.")] + public static SKDocument CreatePdf (Stream stream, SKDocumentPdfMetadata metadata) => + CreatePdf (stream, new SKPdfMetadata (metadata)); + + [Obsolete ("Use CreatePdf(SKWStream, SKPdfMetadata) instead.")] + public static SKDocument CreatePdf (SKWStream stream, SKDocumentPdfMetadata metadata) => + CreatePdf (stream, new SKPdfMetadata (metadata)); + + public static SKDocument CreatePdf (string path, SKPdfMetadata metadata) + { + if (path is null) { + throw new ArgumentNullException (nameof (path)); } - public static SKDocument CreatePdf (SKWStream stream) - { - if (stream == null) { - throw new ArgumentNullException (nameof (stream)); - } + var stream = SKFileWStream.OpenStream (path); + return Owned (CreatePdf (stream, metadata), stream); + } - return Referenced (GetObject (SkiaApi.sk_document_create_pdf_from_stream (stream.Handle)), stream); + public static SKDocument CreatePdf (Stream stream, SKPdfMetadata metadata) + { + if (stream == null) { + throw new ArgumentNullException (nameof (stream)); } - public static SKDocument CreatePdf (string path, float dpi) => - CreatePdf (path, new SKDocumentPdfMetadata (dpi)); + var managed = new SKManagedWStream (stream); + return Owned (CreatePdf (managed, metadata), managed); + } - public static SKDocument CreatePdf (Stream stream, float dpi) => - CreatePdf (stream, new SKDocumentPdfMetadata (dpi)); + public static SKDocument CreatePdf (SKWStream stream, SKPdfMetadata metadata) + { + if (stream is null) { + throw new ArgumentNullException (nameof (stream)); + } - public static SKDocument CreatePdf (SKWStream stream, float dpi) => - CreatePdf (stream, new SKDocumentPdfMetadata (dpi)); + var (metadataHandle, structureHandle) = ToNative (metadata); - public static SKDocument CreatePdf (string path, SKDocumentPdfMetadata metadata) - { - if (path == null) { - throw new ArgumentNullException (nameof (path)); - } + try { + return Referenced (GetObject (SkiaApi.sk_document_create_pdf_from_stream_with_metadata (stream.Handle, metadataHandle)), stream); + } finally { + if (metadataHandle != IntPtr.Zero) + SkiaApi.sk_pdf_metadata_delete (metadataHandle); - var stream = SKFileWStream.OpenStream (path); - return Owned (CreatePdf (stream, metadata), stream); + // dispose because the root node is not owned + if (structureHandle != IntPtr.Zero) + SkiaApi.sk_pdf_structure_element_delete (structureHandle); } + } - public static SKDocument CreatePdf (Stream stream, SKDocumentPdfMetadata metadata) - { - if (stream == null) { - throw new ArgumentNullException (nameof (stream)); - } + internal static SKDocument? GetObject (IntPtr handle) => + handle == IntPtr.Zero ? null : new SKDocument (handle, true); + + private static (IntPtr Metadata, IntPtr Structure) ToNative (SKPdfMetadata metadata) + { + var metadataHandle = SkiaApi.sk_pdf_metadata_new (); - var managed = new SKManagedWStream (stream); - return Owned (CreatePdf (managed, metadata), managed); + if (metadata.Title is not null) { + using var title = SKString.CreateRaw (metadata.Title); + SkiaApi.sk_pdf_metadata_set_title (metadataHandle, title.Handle); + } + if (metadata.Author is not null) { + using var author = SKString.CreateRaw (metadata.Author); + SkiaApi.sk_pdf_metadata_set_author (metadataHandle, author.Handle); + } + if (metadata.Subject is not null) { + using var subject = SKString.CreateRaw (metadata.Subject); + SkiaApi.sk_pdf_metadata_set_subject (metadataHandle, subject.Handle); + } + if (metadata.Keywords is not null) { + using var keywords = SKString.CreateRaw (metadata.Keywords); + SkiaApi.sk_pdf_metadata_set_keywords (metadataHandle, keywords.Handle); + } + if (metadata.Creator is not null) { + using var creator = SKString.CreateRaw (metadata.Creator); + SkiaApi.sk_pdf_metadata_set_creator (metadataHandle, creator.Handle); + } + if (metadata.Producer is not null) { + using var producer = SKString.CreateRaw (metadata.Producer); + SkiaApi.sk_pdf_metadata_set_producer (metadataHandle, producer.Handle); + } + if (metadata.Creation is not null) { + var creation = SKTimeDateTimeInternal.Create (metadata.Creation.Value); + SkiaApi.sk_pdf_metadata_set_creation (metadataHandle, &creation); + } + if (metadata.Modified is not null) { + var modified = SKTimeDateTimeInternal.Create (metadata.Modified.Value); + SkiaApi.sk_pdf_metadata_set_modified (metadataHandle, &modified); } - public static SKDocument CreatePdf (SKWStream stream, SKDocumentPdfMetadata metadata) + SkiaApi.sk_pdf_metadata_set_raster_dpi (metadataHandle, metadata.RasterDpi); + SkiaApi.sk_pdf_metadata_set_pdfa (metadataHandle, metadata.PdfA); + SkiaApi.sk_pdf_metadata_set_encoding_quality (metadataHandle, metadata.EncodingQuality); + SkiaApi.sk_pdf_metadata_set_compression_level (metadataHandle, metadata.Compression); + + IntPtr structureHandle; + if (metadata.Structure is not null) { + structureHandle = ToNative (metadata.Structure); + SkiaApi.sk_pdf_metadata_set_structure_element_tree_root (metadataHandle, structureHandle); + } else { + structureHandle = IntPtr.Zero; + } + + return (metadataHandle, structureHandle); + } + + private static IntPtr ToNative (SKPdfStructureElementNode? structure) + { + if (structure is null) + return IntPtr.Zero; + + var handle = SkiaApi.sk_pdf_structure_element_new (); + + SkiaApi.sk_pdf_structure_element_set_node_id (handle, structure.Id); + +#if NET5_0_OR_GREATER + if (structure.AdditionalNodeIds is List nodes) { + var span = CollectionsMarshal.AsSpan (nodes); + fixed (int* ptr = span) { + SkiaApi.sk_pdf_structure_element_add_additional_node_ids (handle, ptr, span.Length); + } + } else +#endif { - if (stream == null) { - throw new ArgumentNullException (nameof (stream)); + using var nodesArray = Utils.ToRentedArray (structure.AdditionalNodeIds); + fixed (int* ptr = nodesArray) { + SkiaApi.sk_pdf_structure_element_add_additional_node_ids (handle, ptr, (IntPtr)nodesArray.Length); } + } - using var title = SKString.Create (metadata.Title); - using var author = SKString.Create (metadata.Author); - using var subject = SKString.Create (metadata.Subject); - using var keywords = SKString.Create (metadata.Keywords); - using var creator = SKString.Create (metadata.Creator); - using var producer = SKString.Create (metadata.Producer); - - var cmetadata = new SKDocumentPdfMetadataInternal { - fTitle = title?.Handle ?? IntPtr.Zero, - fAuthor = author?.Handle ?? IntPtr.Zero, - fSubject = subject?.Handle ?? IntPtr.Zero, - fKeywords = keywords?.Handle ?? IntPtr.Zero, - fCreator = creator?.Handle ?? IntPtr.Zero, - fProducer = producer?.Handle ?? IntPtr.Zero, - fRasterDPI = metadata.RasterDpi, - fPDFA = metadata.PdfA ? (byte)1 : (byte)0, - fEncodingQuality = metadata.EncodingQuality, - }; - - SKTimeDateTimeInternal creation; - if (metadata.Creation != null) { - creation = SKTimeDateTimeInternal.Create (metadata.Creation.Value); - cmetadata.fCreation = &creation; - } - SKTimeDateTimeInternal modified; - if (metadata.Modified != null) { - modified = SKTimeDateTimeInternal.Create (metadata.Modified.Value); - cmetadata.fModified = &modified; + using var type = SKString.CreateRaw (structure.Type); + SkiaApi.sk_pdf_structure_element_set_type_string (handle, type.Handle); + + using var alt = SKString.CreateRaw (structure.Alt); + SkiaApi.sk_pdf_structure_element_set_alt (handle, alt.Handle); + + using var lang = SKString.CreateRaw (structure.Language); + SkiaApi.sk_pdf_structure_element_set_lang (handle, lang.Handle); + + if (structure.Attributes.Inner.Count > 0) { + foreach (var (owner, name, val) in structure.Attributes.Inner) { + switch (val) { + case int intValue: + SkiaApi.sk_pdf_structure_element_add_int_attribute (handle, owner, name, intValue); + break; + case float floatValue: + SkiaApi.sk_pdf_structure_element_add_float_attribute (handle, owner, name, floatValue); + break; + case string stringValue: + SkiaApi.sk_pdf_structure_element_add_name_attribute (handle, owner, name, stringValue); + break; + case int[] intArray: + fixed (int* ptr = intArray) { + SkiaApi.sk_pdf_structure_element_add_node_id_array_attribute (handle, owner, name, ptr, (IntPtr)intArray.Length); + } + break; + case float[] floatArray: + fixed (float* ptr = floatArray) { + SkiaApi.sk_pdf_structure_element_add_float_array_attribute (handle, owner, name, ptr, (IntPtr)floatArray.Length); + } + break; + default: + // TODO + break; + } } + } - return Referenced (GetObject (SkiaApi.sk_document_create_pdf_from_stream_with_metadata (stream.Handle, &cmetadata)), stream); + if (structure.Children.Count > 0) { + foreach (var child in structure.Children) { + // do not dispose as the parent takes ownership + var childHandle = ToNative (child); + if (childHandle == IntPtr.Zero) + continue; + SkiaApi.sk_pdf_structure_element_add_child (handle, childHandle); + } } - internal static SKDocument GetObject (IntPtr handle) => - handle == IntPtr.Zero ? null : new SKDocument (handle, true); + return handle; + } +} + +public static class SkPdfDocumentExtensions +{ + public static void DrawPdfNodeAnnotation (this SKCanvas canvas, int nodeId) + { + if (canvas is null) + throw new ArgumentNullException (nameof (canvas)); + + SkiaApi.sk_canvas_draw_pdf_node_id_annotation (canvas.Handle, nodeId); } } diff --git a/binding/SkiaSharp/SKPdfMetadata.cs b/binding/SkiaSharp/SKPdfMetadata.cs new file mode 100644 index 0000000000..ca8655b577 --- /dev/null +++ b/binding/SkiaSharp/SKPdfMetadata.cs @@ -0,0 +1,106 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace SkiaSharp; + +public class SKPdfMetadata +{ + public const float DefaultRasterDpi = SKDocument.DefaultRasterDpi; + + public const int DefaultEncodingQuality = 101; + + public SKPdfMetadata () + { + } + + internal SKPdfMetadata (SKDocumentPdfMetadata metadata) + { + Title = metadata.Title; + Author = metadata.Author; + Subject = metadata.Subject; + Keywords = metadata.Keywords; + Creator = metadata.Creator; + Producer = metadata.Producer; + Creation = metadata.Creation; + Modified = metadata.Modified; + RasterDpi = metadata.RasterDpi; + PdfA = metadata.PdfA; + EncodingQuality = metadata.EncodingQuality; + } + + public string? Title { get; set; } + + public string? Author { get; set; } + + public string? Subject { get; set; } + + public string? Keywords { get; set; } + + public string? Creator { get; set; } + + public string? Producer { get; set; } + + public DateTime? Creation { get; set; } + + public DateTime? Modified { get; set; } + + public float RasterDpi { get; set; } = DefaultRasterDpi; + + public bool PdfA { get; set; } + + public int EncodingQuality { get; set; } = DefaultEncodingQuality; + + public SKPdfCompression Compression { get; set; } = SKPdfCompression.Default; + + public SKPdfStructureElementNode? Structure { get; set; } +} + +public class SKPdfStructureElementNode +{ + private List? children; + private List? additionalNodeIds; + private SKPdfAttributeList? attributes; + + public SKPdfStructureElementNode (int id, string type) + { + Id = id; + Type = type; + } + + public int Id { get; } + + public string Type { get; } + + public string? Alt { get; set; } + + public string? Language { get; set; } + + public IList Children => children ??= new (); + + public IList AdditionalNodeIds => additionalNodeIds ??= new (); + + public SKPdfAttributeList Attributes => attributes ??= new (); +} + +public class SKPdfAttributeList +{ + private List<(string Owner, string Name, object Value)> attributes = new (); + + internal IReadOnlyList<(string Owner, string Name, object Value)> Inner => attributes; + + public void Add (string owner, string name, int value) => + attributes.Add ((owner, name, value)); + + public void Add (string owner, string name, float value) => + attributes.Add ((owner, name, value)); + + public void Add (string owner, string name, string value) => + attributes.Add ((owner, name, value)); + + public void Add (string owner, string name, IEnumerable value) => + attributes.Add ((owner, name, value.ToArray ())); + + public void Add (string owner, string name, IEnumerable value) => + attributes.Add ((owner, name, value.ToArray ())); +} diff --git a/binding/SkiaSharp/SKString.cs b/binding/SkiaSharp/SKString.cs index b48a84f23f..cc96c020fe 100644 --- a/binding/SkiaSharp/SKString.cs +++ b/binding/SkiaSharp/SKString.cs @@ -1,7 +1,8 @@ -#nullable disable - -using System; -using System.Runtime.InteropServices; +using System; +using System.Diagnostics.CodeAnalysis; +#if NETSTANDARD1_3 || WINDOWS_UWP +using System.Reflection; +#endif namespace SkiaSharp { @@ -19,32 +20,35 @@ public SKString () throw new InvalidOperationException ("Unable to create a new SKString instance."); } } - - public SKString (byte [] src, long length) + + public SKString (ReadOnlySpan src, long length) : base (CreateCopy (src, length), true) { if (Handle == IntPtr.Zero) { throw new InvalidOperationException ("Unable to copy the SKString instance."); } } - - private static IntPtr CreateCopy (byte [] src, long length) + + private static IntPtr CreateCopy (ReadOnlySpan src, long length) { + if (length > src.Length) + throw new ArgumentOutOfRangeException (nameof (length)); + fixed (byte* s = src) { return SkiaApi.sk_string_new_with_copy (s, (IntPtr)length); } } - public SKString (byte [] src) + public SKString (ReadOnlySpan src) : this (src, src.Length) { } - + public SKString (string str) : this (StringUtilities.GetEncodedText (str, SKTextEncoding.Utf8)) { } - + public override string ToString () { var cstr = SkiaApi.sk_string_get_c_str (Handle); @@ -56,23 +60,64 @@ public static explicit operator string (SKString skString) { return skString.ToString (); } - - internal static SKString Create (string str) + + [return: NotNullIfNotNull (nameof (str))] + internal static SKString? Create (string? str) { - if (str == null) { + if (str is null) { return null; } return new SKString (str); } + internal static SKStringRaw CreateRaw (string? str) => + new SKStringRaw (str); + protected override void Dispose (bool disposing) => base.Dispose (disposing); protected override void DisposeNative () => SkiaApi.sk_string_destructor (Handle); - internal static SKString GetObject (IntPtr handle) => + internal static SKString? GetObject (IntPtr handle) => handle == IntPtr.Zero ? null : new SKString (handle, true); + + internal readonly ref struct SKStringRaw + { + public SKStringRaw () + { + Handle = IntPtr.Zero; + } + + public SKStringRaw (string? text) + : this (text.AsSpan ()) + { + } + + public SKStringRaw (ReadOnlySpan text) + { + if (text.Length == 0) { + Handle = IntPtr.Zero; + return; + } + + var bufferSize = StringUtilities.GetMaxByteCount (text, SKTextEncoding.Utf8); + var buffer = stackalloc byte[bufferSize]; + var bufferSpan = new Span (buffer, bufferSize); + + var bytesSize = StringUtilities.GetEncodedText (text, bufferSpan, SKTextEncoding.Utf8); + + Handle = SkiaApi.sk_string_new_with_copy (buffer, (IntPtr)bytesSize); + } + + public readonly IntPtr Handle; + + public void Dispose () + { + if (Handle != IntPtr.Zero) + SkiaApi.sk_string_destructor (Handle); + } + } } } diff --git a/binding/SkiaSharp/SkiaApi.generated.cs b/binding/SkiaSharp/SkiaApi.generated.cs index 4f038f0077..71ce95a913 100644 --- a/binding/SkiaSharp/SkiaApi.generated.cs +++ b/binding/SkiaSharp/SkiaApi.generated.cs @@ -50,6 +50,8 @@ using sk_path_rawiterator_t = System.IntPtr; using sk_path_t = System.IntPtr; using sk_pathmeasure_t = System.IntPtr; +using sk_pdf_metadata_t = System.IntPtr; +using sk_pdf_structure_element_t = System.IntPtr; using sk_picture_recorder_t = System.IntPtr; using sk_picture_t = System.IntPtr; using sk_pixelref_factory_t = System.IntPtr; @@ -4974,6 +4976,25 @@ internal static void sk_data_unref (sk_data_t param0) => #region sk_document.h + // void sk_canvas_draw_pdf_node_id_annotation(sk_canvas_t* t, int nodeId) + #if !USE_DELEGATES + #if USE_LIBRARY_IMPORT + [LibraryImport (SKIA)] + internal static partial void sk_canvas_draw_pdf_node_id_annotation (sk_canvas_t t, Int32 nodeId); + #else // !USE_LIBRARY_IMPORT + [DllImport (SKIA, CallingConvention = CallingConvention.Cdecl)] + internal static extern void sk_canvas_draw_pdf_node_id_annotation (sk_canvas_t t, Int32 nodeId); + #endif + #else + private partial class Delegates { + [UnmanagedFunctionPointer (CallingConvention.Cdecl)] + internal delegate void sk_canvas_draw_pdf_node_id_annotation (sk_canvas_t t, Int32 nodeId); + } + private static Delegates.sk_canvas_draw_pdf_node_id_annotation sk_canvas_draw_pdf_node_id_annotation_delegate; + internal static void sk_canvas_draw_pdf_node_id_annotation (sk_canvas_t t, Int32 nodeId) => + (sk_canvas_draw_pdf_node_id_annotation_delegate ??= GetSymbol ("sk_canvas_draw_pdf_node_id_annotation")).Invoke (t, nodeId); + #endif + // void sk_document_abort(sk_document_t* document) #if !USE_DELEGATES #if USE_LIBRARY_IMPORT @@ -5050,22 +5071,22 @@ internal static sk_document_t sk_document_create_pdf_from_stream (sk_wstream_t s (sk_document_create_pdf_from_stream_delegate ??= GetSymbol ("sk_document_create_pdf_from_stream")).Invoke (stream); #endif - // sk_document_t* sk_document_create_pdf_from_stream_with_metadata(sk_wstream_t* stream, const sk_document_pdf_metadata_t* metadata) + // sk_document_t* sk_document_create_pdf_from_stream_with_metadata(sk_wstream_t* stream, const sk_pdf_metadata_t* metadata) #if !USE_DELEGATES #if USE_LIBRARY_IMPORT [LibraryImport (SKIA)] - internal static partial sk_document_t sk_document_create_pdf_from_stream_with_metadata (sk_wstream_t stream, SKDocumentPdfMetadataInternal* metadata); + internal static partial sk_document_t sk_document_create_pdf_from_stream_with_metadata (sk_wstream_t stream, sk_pdf_metadata_t metadata); #else // !USE_LIBRARY_IMPORT [DllImport (SKIA, CallingConvention = CallingConvention.Cdecl)] - internal static extern sk_document_t sk_document_create_pdf_from_stream_with_metadata (sk_wstream_t stream, SKDocumentPdfMetadataInternal* metadata); + internal static extern sk_document_t sk_document_create_pdf_from_stream_with_metadata (sk_wstream_t stream, sk_pdf_metadata_t metadata); #endif #else private partial class Delegates { [UnmanagedFunctionPointer (CallingConvention.Cdecl)] - internal delegate sk_document_t sk_document_create_pdf_from_stream_with_metadata (sk_wstream_t stream, SKDocumentPdfMetadataInternal* metadata); + internal delegate sk_document_t sk_document_create_pdf_from_stream_with_metadata (sk_wstream_t stream, sk_pdf_metadata_t metadata); } private static Delegates.sk_document_create_pdf_from_stream_with_metadata sk_document_create_pdf_from_stream_with_metadata_delegate; - internal static sk_document_t sk_document_create_pdf_from_stream_with_metadata (sk_wstream_t stream, SKDocumentPdfMetadataInternal* metadata) => + internal static sk_document_t sk_document_create_pdf_from_stream_with_metadata (sk_wstream_t stream, sk_pdf_metadata_t metadata) => (sk_document_create_pdf_from_stream_with_metadata_delegate ??= GetSymbol ("sk_document_create_pdf_from_stream_with_metadata")).Invoke (stream, metadata); #endif @@ -5126,6 +5147,557 @@ internal static void sk_document_unref (sk_document_t document) => (sk_document_unref_delegate ??= GetSymbol ("sk_document_unref")).Invoke (document); #endif + // void sk_pdf_metadata_delete(sk_pdf_metadata_t* metadata) + #if !USE_DELEGATES + #if USE_LIBRARY_IMPORT + [LibraryImport (SKIA)] + internal static partial void sk_pdf_metadata_delete (sk_pdf_metadata_t metadata); + #else // !USE_LIBRARY_IMPORT + [DllImport (SKIA, CallingConvention = CallingConvention.Cdecl)] + internal static extern void sk_pdf_metadata_delete (sk_pdf_metadata_t metadata); + #endif + #else + private partial class Delegates { + [UnmanagedFunctionPointer (CallingConvention.Cdecl)] + internal delegate void sk_pdf_metadata_delete (sk_pdf_metadata_t metadata); + } + private static Delegates.sk_pdf_metadata_delete sk_pdf_metadata_delete_delegate; + internal static void sk_pdf_metadata_delete (sk_pdf_metadata_t metadata) => + (sk_pdf_metadata_delete_delegate ??= GetSymbol ("sk_pdf_metadata_delete")).Invoke (metadata); + #endif + + // sk_pdf_metadata_t* sk_pdf_metadata_new() + #if !USE_DELEGATES + #if USE_LIBRARY_IMPORT + [LibraryImport (SKIA)] + internal static partial sk_pdf_metadata_t sk_pdf_metadata_new (); + #else // !USE_LIBRARY_IMPORT + [DllImport (SKIA, CallingConvention = CallingConvention.Cdecl)] + internal static extern sk_pdf_metadata_t sk_pdf_metadata_new (); + #endif + #else + private partial class Delegates { + [UnmanagedFunctionPointer (CallingConvention.Cdecl)] + internal delegate sk_pdf_metadata_t sk_pdf_metadata_new (); + } + private static Delegates.sk_pdf_metadata_new sk_pdf_metadata_new_delegate; + internal static sk_pdf_metadata_t sk_pdf_metadata_new () => + (sk_pdf_metadata_new_delegate ??= GetSymbol ("sk_pdf_metadata_new")).Invoke (); + #endif + + // void sk_pdf_metadata_set_author(sk_pdf_metadata_t* metadata, sk_string_t* value) + #if !USE_DELEGATES + #if USE_LIBRARY_IMPORT + [LibraryImport (SKIA)] + internal static partial void sk_pdf_metadata_set_author (sk_pdf_metadata_t metadata, sk_string_t value); + #else // !USE_LIBRARY_IMPORT + [DllImport (SKIA, CallingConvention = CallingConvention.Cdecl)] + internal static extern void sk_pdf_metadata_set_author (sk_pdf_metadata_t metadata, sk_string_t value); + #endif + #else + private partial class Delegates { + [UnmanagedFunctionPointer (CallingConvention.Cdecl)] + internal delegate void sk_pdf_metadata_set_author (sk_pdf_metadata_t metadata, sk_string_t value); + } + private static Delegates.sk_pdf_metadata_set_author sk_pdf_metadata_set_author_delegate; + internal static void sk_pdf_metadata_set_author (sk_pdf_metadata_t metadata, sk_string_t value) => + (sk_pdf_metadata_set_author_delegate ??= GetSymbol ("sk_pdf_metadata_set_author")).Invoke (metadata, value); + #endif + + // void sk_pdf_metadata_set_compression_level(sk_pdf_metadata_t* metadata, sk_pdf_compression_t value) + #if !USE_DELEGATES + #if USE_LIBRARY_IMPORT + [LibraryImport (SKIA)] + internal static partial void sk_pdf_metadata_set_compression_level (sk_pdf_metadata_t metadata, SKPdfCompression value); + #else // !USE_LIBRARY_IMPORT + [DllImport (SKIA, CallingConvention = CallingConvention.Cdecl)] + internal static extern void sk_pdf_metadata_set_compression_level (sk_pdf_metadata_t metadata, SKPdfCompression value); + #endif + #else + private partial class Delegates { + [UnmanagedFunctionPointer (CallingConvention.Cdecl)] + internal delegate void sk_pdf_metadata_set_compression_level (sk_pdf_metadata_t metadata, SKPdfCompression value); + } + private static Delegates.sk_pdf_metadata_set_compression_level sk_pdf_metadata_set_compression_level_delegate; + internal static void sk_pdf_metadata_set_compression_level (sk_pdf_metadata_t metadata, SKPdfCompression value) => + (sk_pdf_metadata_set_compression_level_delegate ??= GetSymbol ("sk_pdf_metadata_set_compression_level")).Invoke (metadata, value); + #endif + + // void sk_pdf_metadata_set_creation(sk_pdf_metadata_t* metadata, sk_time_datetime_t* value) + #if !USE_DELEGATES + #if USE_LIBRARY_IMPORT + [LibraryImport (SKIA)] + internal static partial void sk_pdf_metadata_set_creation (sk_pdf_metadata_t metadata, SKTimeDateTimeInternal* value); + #else // !USE_LIBRARY_IMPORT + [DllImport (SKIA, CallingConvention = CallingConvention.Cdecl)] + internal static extern void sk_pdf_metadata_set_creation (sk_pdf_metadata_t metadata, SKTimeDateTimeInternal* value); + #endif + #else + private partial class Delegates { + [UnmanagedFunctionPointer (CallingConvention.Cdecl)] + internal delegate void sk_pdf_metadata_set_creation (sk_pdf_metadata_t metadata, SKTimeDateTimeInternal* value); + } + private static Delegates.sk_pdf_metadata_set_creation sk_pdf_metadata_set_creation_delegate; + internal static void sk_pdf_metadata_set_creation (sk_pdf_metadata_t metadata, SKTimeDateTimeInternal* value) => + (sk_pdf_metadata_set_creation_delegate ??= GetSymbol ("sk_pdf_metadata_set_creation")).Invoke (metadata, value); + #endif + + // void sk_pdf_metadata_set_creator(sk_pdf_metadata_t* metadata, sk_string_t* value) + #if !USE_DELEGATES + #if USE_LIBRARY_IMPORT + [LibraryImport (SKIA)] + internal static partial void sk_pdf_metadata_set_creator (sk_pdf_metadata_t metadata, sk_string_t value); + #else // !USE_LIBRARY_IMPORT + [DllImport (SKIA, CallingConvention = CallingConvention.Cdecl)] + internal static extern void sk_pdf_metadata_set_creator (sk_pdf_metadata_t metadata, sk_string_t value); + #endif + #else + private partial class Delegates { + [UnmanagedFunctionPointer (CallingConvention.Cdecl)] + internal delegate void sk_pdf_metadata_set_creator (sk_pdf_metadata_t metadata, sk_string_t value); + } + private static Delegates.sk_pdf_metadata_set_creator sk_pdf_metadata_set_creator_delegate; + internal static void sk_pdf_metadata_set_creator (sk_pdf_metadata_t metadata, sk_string_t value) => + (sk_pdf_metadata_set_creator_delegate ??= GetSymbol ("sk_pdf_metadata_set_creator")).Invoke (metadata, value); + #endif + + // void sk_pdf_metadata_set_encoding_quality(sk_pdf_metadata_t* metadata, int value) + #if !USE_DELEGATES + #if USE_LIBRARY_IMPORT + [LibraryImport (SKIA)] + internal static partial void sk_pdf_metadata_set_encoding_quality (sk_pdf_metadata_t metadata, Int32 value); + #else // !USE_LIBRARY_IMPORT + [DllImport (SKIA, CallingConvention = CallingConvention.Cdecl)] + internal static extern void sk_pdf_metadata_set_encoding_quality (sk_pdf_metadata_t metadata, Int32 value); + #endif + #else + private partial class Delegates { + [UnmanagedFunctionPointer (CallingConvention.Cdecl)] + internal delegate void sk_pdf_metadata_set_encoding_quality (sk_pdf_metadata_t metadata, Int32 value); + } + private static Delegates.sk_pdf_metadata_set_encoding_quality sk_pdf_metadata_set_encoding_quality_delegate; + internal static void sk_pdf_metadata_set_encoding_quality (sk_pdf_metadata_t metadata, Int32 value) => + (sk_pdf_metadata_set_encoding_quality_delegate ??= GetSymbol ("sk_pdf_metadata_set_encoding_quality")).Invoke (metadata, value); + #endif + + // void sk_pdf_metadata_set_keywords(sk_pdf_metadata_t* metadata, sk_string_t* value) + #if !USE_DELEGATES + #if USE_LIBRARY_IMPORT + [LibraryImport (SKIA)] + internal static partial void sk_pdf_metadata_set_keywords (sk_pdf_metadata_t metadata, sk_string_t value); + #else // !USE_LIBRARY_IMPORT + [DllImport (SKIA, CallingConvention = CallingConvention.Cdecl)] + internal static extern void sk_pdf_metadata_set_keywords (sk_pdf_metadata_t metadata, sk_string_t value); + #endif + #else + private partial class Delegates { + [UnmanagedFunctionPointer (CallingConvention.Cdecl)] + internal delegate void sk_pdf_metadata_set_keywords (sk_pdf_metadata_t metadata, sk_string_t value); + } + private static Delegates.sk_pdf_metadata_set_keywords sk_pdf_metadata_set_keywords_delegate; + internal static void sk_pdf_metadata_set_keywords (sk_pdf_metadata_t metadata, sk_string_t value) => + (sk_pdf_metadata_set_keywords_delegate ??= GetSymbol ("sk_pdf_metadata_set_keywords")).Invoke (metadata, value); + #endif + + // void sk_pdf_metadata_set_modified(sk_pdf_metadata_t* metadata, sk_time_datetime_t* value) + #if !USE_DELEGATES + #if USE_LIBRARY_IMPORT + [LibraryImport (SKIA)] + internal static partial void sk_pdf_metadata_set_modified (sk_pdf_metadata_t metadata, SKTimeDateTimeInternal* value); + #else // !USE_LIBRARY_IMPORT + [DllImport (SKIA, CallingConvention = CallingConvention.Cdecl)] + internal static extern void sk_pdf_metadata_set_modified (sk_pdf_metadata_t metadata, SKTimeDateTimeInternal* value); + #endif + #else + private partial class Delegates { + [UnmanagedFunctionPointer (CallingConvention.Cdecl)] + internal delegate void sk_pdf_metadata_set_modified (sk_pdf_metadata_t metadata, SKTimeDateTimeInternal* value); + } + private static Delegates.sk_pdf_metadata_set_modified sk_pdf_metadata_set_modified_delegate; + internal static void sk_pdf_metadata_set_modified (sk_pdf_metadata_t metadata, SKTimeDateTimeInternal* value) => + (sk_pdf_metadata_set_modified_delegate ??= GetSymbol ("sk_pdf_metadata_set_modified")).Invoke (metadata, value); + #endif + + // void sk_pdf_metadata_set_pdfa(sk_pdf_metadata_t* metadata, bool value) + #if !USE_DELEGATES + #if USE_LIBRARY_IMPORT + [LibraryImport (SKIA)] + internal static partial void sk_pdf_metadata_set_pdfa (sk_pdf_metadata_t metadata, [MarshalAs (UnmanagedType.I1)] bool value); + #else // !USE_LIBRARY_IMPORT + [DllImport (SKIA, CallingConvention = CallingConvention.Cdecl)] + internal static extern void sk_pdf_metadata_set_pdfa (sk_pdf_metadata_t metadata, [MarshalAs (UnmanagedType.I1)] bool value); + #endif + #else + private partial class Delegates { + [UnmanagedFunctionPointer (CallingConvention.Cdecl)] + internal delegate void sk_pdf_metadata_set_pdfa (sk_pdf_metadata_t metadata, [MarshalAs (UnmanagedType.I1)] bool value); + } + private static Delegates.sk_pdf_metadata_set_pdfa sk_pdf_metadata_set_pdfa_delegate; + internal static void sk_pdf_metadata_set_pdfa (sk_pdf_metadata_t metadata, [MarshalAs (UnmanagedType.I1)] bool value) => + (sk_pdf_metadata_set_pdfa_delegate ??= GetSymbol ("sk_pdf_metadata_set_pdfa")).Invoke (metadata, value); + #endif + + // void sk_pdf_metadata_set_producer(sk_pdf_metadata_t* metadata, sk_string_t* value) + #if !USE_DELEGATES + #if USE_LIBRARY_IMPORT + [LibraryImport (SKIA)] + internal static partial void sk_pdf_metadata_set_producer (sk_pdf_metadata_t metadata, sk_string_t value); + #else // !USE_LIBRARY_IMPORT + [DllImport (SKIA, CallingConvention = CallingConvention.Cdecl)] + internal static extern void sk_pdf_metadata_set_producer (sk_pdf_metadata_t metadata, sk_string_t value); + #endif + #else + private partial class Delegates { + [UnmanagedFunctionPointer (CallingConvention.Cdecl)] + internal delegate void sk_pdf_metadata_set_producer (sk_pdf_metadata_t metadata, sk_string_t value); + } + private static Delegates.sk_pdf_metadata_set_producer sk_pdf_metadata_set_producer_delegate; + internal static void sk_pdf_metadata_set_producer (sk_pdf_metadata_t metadata, sk_string_t value) => + (sk_pdf_metadata_set_producer_delegate ??= GetSymbol ("sk_pdf_metadata_set_producer")).Invoke (metadata, value); + #endif + + // void sk_pdf_metadata_set_raster_dpi(sk_pdf_metadata_t* metadata, float value) + #if !USE_DELEGATES + #if USE_LIBRARY_IMPORT + [LibraryImport (SKIA)] + internal static partial void sk_pdf_metadata_set_raster_dpi (sk_pdf_metadata_t metadata, Single value); + #else // !USE_LIBRARY_IMPORT + [DllImport (SKIA, CallingConvention = CallingConvention.Cdecl)] + internal static extern void sk_pdf_metadata_set_raster_dpi (sk_pdf_metadata_t metadata, Single value); + #endif + #else + private partial class Delegates { + [UnmanagedFunctionPointer (CallingConvention.Cdecl)] + internal delegate void sk_pdf_metadata_set_raster_dpi (sk_pdf_metadata_t metadata, Single value); + } + private static Delegates.sk_pdf_metadata_set_raster_dpi sk_pdf_metadata_set_raster_dpi_delegate; + internal static void sk_pdf_metadata_set_raster_dpi (sk_pdf_metadata_t metadata, Single value) => + (sk_pdf_metadata_set_raster_dpi_delegate ??= GetSymbol ("sk_pdf_metadata_set_raster_dpi")).Invoke (metadata, value); + #endif + + // void sk_pdf_metadata_set_structure_element_tree_root(sk_pdf_metadata_t* metadata, sk_pdf_structure_element_t* value) + #if !USE_DELEGATES + #if USE_LIBRARY_IMPORT + [LibraryImport (SKIA)] + internal static partial void sk_pdf_metadata_set_structure_element_tree_root (sk_pdf_metadata_t metadata, sk_pdf_structure_element_t value); + #else // !USE_LIBRARY_IMPORT + [DllImport (SKIA, CallingConvention = CallingConvention.Cdecl)] + internal static extern void sk_pdf_metadata_set_structure_element_tree_root (sk_pdf_metadata_t metadata, sk_pdf_structure_element_t value); + #endif + #else + private partial class Delegates { + [UnmanagedFunctionPointer (CallingConvention.Cdecl)] + internal delegate void sk_pdf_metadata_set_structure_element_tree_root (sk_pdf_metadata_t metadata, sk_pdf_structure_element_t value); + } + private static Delegates.sk_pdf_metadata_set_structure_element_tree_root sk_pdf_metadata_set_structure_element_tree_root_delegate; + internal static void sk_pdf_metadata_set_structure_element_tree_root (sk_pdf_metadata_t metadata, sk_pdf_structure_element_t value) => + (sk_pdf_metadata_set_structure_element_tree_root_delegate ??= GetSymbol ("sk_pdf_metadata_set_structure_element_tree_root")).Invoke (metadata, value); + #endif + + // void sk_pdf_metadata_set_subject(sk_pdf_metadata_t* metadata, sk_string_t* value) + #if !USE_DELEGATES + #if USE_LIBRARY_IMPORT + [LibraryImport (SKIA)] + internal static partial void sk_pdf_metadata_set_subject (sk_pdf_metadata_t metadata, sk_string_t value); + #else // !USE_LIBRARY_IMPORT + [DllImport (SKIA, CallingConvention = CallingConvention.Cdecl)] + internal static extern void sk_pdf_metadata_set_subject (sk_pdf_metadata_t metadata, sk_string_t value); + #endif + #else + private partial class Delegates { + [UnmanagedFunctionPointer (CallingConvention.Cdecl)] + internal delegate void sk_pdf_metadata_set_subject (sk_pdf_metadata_t metadata, sk_string_t value); + } + private static Delegates.sk_pdf_metadata_set_subject sk_pdf_metadata_set_subject_delegate; + internal static void sk_pdf_metadata_set_subject (sk_pdf_metadata_t metadata, sk_string_t value) => + (sk_pdf_metadata_set_subject_delegate ??= GetSymbol ("sk_pdf_metadata_set_subject")).Invoke (metadata, value); + #endif + + // void sk_pdf_metadata_set_title(sk_pdf_metadata_t* metadata, sk_string_t* value) + #if !USE_DELEGATES + #if USE_LIBRARY_IMPORT + [LibraryImport (SKIA)] + internal static partial void sk_pdf_metadata_set_title (sk_pdf_metadata_t metadata, sk_string_t value); + #else // !USE_LIBRARY_IMPORT + [DllImport (SKIA, CallingConvention = CallingConvention.Cdecl)] + internal static extern void sk_pdf_metadata_set_title (sk_pdf_metadata_t metadata, sk_string_t value); + #endif + #else + private partial class Delegates { + [UnmanagedFunctionPointer (CallingConvention.Cdecl)] + internal delegate void sk_pdf_metadata_set_title (sk_pdf_metadata_t metadata, sk_string_t value); + } + private static Delegates.sk_pdf_metadata_set_title sk_pdf_metadata_set_title_delegate; + internal static void sk_pdf_metadata_set_title (sk_pdf_metadata_t metadata, sk_string_t value) => + (sk_pdf_metadata_set_title_delegate ??= GetSymbol ("sk_pdf_metadata_set_title")).Invoke (metadata, value); + #endif + + // void sk_pdf_structure_element_add_additional_node_id(sk_pdf_structure_element_t* element, int value) + #if !USE_DELEGATES + #if USE_LIBRARY_IMPORT + [LibraryImport (SKIA)] + internal static partial void sk_pdf_structure_element_add_additional_node_id (sk_pdf_structure_element_t element, Int32 value); + #else // !USE_LIBRARY_IMPORT + [DllImport (SKIA, CallingConvention = CallingConvention.Cdecl)] + internal static extern void sk_pdf_structure_element_add_additional_node_id (sk_pdf_structure_element_t element, Int32 value); + #endif + #else + private partial class Delegates { + [UnmanagedFunctionPointer (CallingConvention.Cdecl)] + internal delegate void sk_pdf_structure_element_add_additional_node_id (sk_pdf_structure_element_t element, Int32 value); + } + private static Delegates.sk_pdf_structure_element_add_additional_node_id sk_pdf_structure_element_add_additional_node_id_delegate; + internal static void sk_pdf_structure_element_add_additional_node_id (sk_pdf_structure_element_t element, Int32 value) => + (sk_pdf_structure_element_add_additional_node_id_delegate ??= GetSymbol ("sk_pdf_structure_element_add_additional_node_id")).Invoke (element, value); + #endif + + // void sk_pdf_structure_element_add_additional_node_ids(sk_pdf_structure_element_t* element, int* value, size_t count) + #if !USE_DELEGATES + #if USE_LIBRARY_IMPORT + [LibraryImport (SKIA)] + internal static partial void sk_pdf_structure_element_add_additional_node_ids (sk_pdf_structure_element_t element, Int32* value, /* size_t */ IntPtr count); + #else // !USE_LIBRARY_IMPORT + [DllImport (SKIA, CallingConvention = CallingConvention.Cdecl)] + internal static extern void sk_pdf_structure_element_add_additional_node_ids (sk_pdf_structure_element_t element, Int32* value, /* size_t */ IntPtr count); + #endif + #else + private partial class Delegates { + [UnmanagedFunctionPointer (CallingConvention.Cdecl)] + internal delegate void sk_pdf_structure_element_add_additional_node_ids (sk_pdf_structure_element_t element, Int32* value, /* size_t */ IntPtr count); + } + private static Delegates.sk_pdf_structure_element_add_additional_node_ids sk_pdf_structure_element_add_additional_node_ids_delegate; + internal static void sk_pdf_structure_element_add_additional_node_ids (sk_pdf_structure_element_t element, Int32* value, /* size_t */ IntPtr count) => + (sk_pdf_structure_element_add_additional_node_ids_delegate ??= GetSymbol ("sk_pdf_structure_element_add_additional_node_ids")).Invoke (element, value, count); + #endif + + // void sk_pdf_structure_element_add_child(sk_pdf_structure_element_t* element, sk_pdf_structure_element_t* value) + #if !USE_DELEGATES + #if USE_LIBRARY_IMPORT + [LibraryImport (SKIA)] + internal static partial void sk_pdf_structure_element_add_child (sk_pdf_structure_element_t element, sk_pdf_structure_element_t value); + #else // !USE_LIBRARY_IMPORT + [DllImport (SKIA, CallingConvention = CallingConvention.Cdecl)] + internal static extern void sk_pdf_structure_element_add_child (sk_pdf_structure_element_t element, sk_pdf_structure_element_t value); + #endif + #else + private partial class Delegates { + [UnmanagedFunctionPointer (CallingConvention.Cdecl)] + internal delegate void sk_pdf_structure_element_add_child (sk_pdf_structure_element_t element, sk_pdf_structure_element_t value); + } + private static Delegates.sk_pdf_structure_element_add_child sk_pdf_structure_element_add_child_delegate; + internal static void sk_pdf_structure_element_add_child (sk_pdf_structure_element_t element, sk_pdf_structure_element_t value) => + (sk_pdf_structure_element_add_child_delegate ??= GetSymbol ("sk_pdf_structure_element_add_child")).Invoke (element, value); + #endif + + // void sk_pdf_structure_element_add_float_array_attribute(sk_pdf_structure_element_t* element, const char* owner, const char* name, float* values, size_t count) + #if !USE_DELEGATES + #if USE_LIBRARY_IMPORT + [LibraryImport (SKIA)] + internal static partial void sk_pdf_structure_element_add_float_array_attribute (sk_pdf_structure_element_t element, [MarshalAs (UnmanagedType.LPStr)] String owner, [MarshalAs (UnmanagedType.LPStr)] String name, Single* values, /* size_t */ IntPtr count); + #else // !USE_LIBRARY_IMPORT + [DllImport (SKIA, CallingConvention = CallingConvention.Cdecl)] + internal static extern void sk_pdf_structure_element_add_float_array_attribute (sk_pdf_structure_element_t element, [MarshalAs (UnmanagedType.LPStr)] String owner, [MarshalAs (UnmanagedType.LPStr)] String name, Single* values, /* size_t */ IntPtr count); + #endif + #else + private partial class Delegates { + [UnmanagedFunctionPointer (CallingConvention.Cdecl)] + internal delegate void sk_pdf_structure_element_add_float_array_attribute (sk_pdf_structure_element_t element, [MarshalAs (UnmanagedType.LPStr)] String owner, [MarshalAs (UnmanagedType.LPStr)] String name, Single* values, /* size_t */ IntPtr count); + } + private static Delegates.sk_pdf_structure_element_add_float_array_attribute sk_pdf_structure_element_add_float_array_attribute_delegate; + internal static void sk_pdf_structure_element_add_float_array_attribute (sk_pdf_structure_element_t element, [MarshalAs (UnmanagedType.LPStr)] String owner, [MarshalAs (UnmanagedType.LPStr)] String name, Single* values, /* size_t */ IntPtr count) => + (sk_pdf_structure_element_add_float_array_attribute_delegate ??= GetSymbol ("sk_pdf_structure_element_add_float_array_attribute")).Invoke (element, owner, name, values, count); + #endif + + // void sk_pdf_structure_element_add_float_attribute(sk_pdf_structure_element_t* element, const char* owner, const char* name, float value) + #if !USE_DELEGATES + #if USE_LIBRARY_IMPORT + [LibraryImport (SKIA)] + internal static partial void sk_pdf_structure_element_add_float_attribute (sk_pdf_structure_element_t element, [MarshalAs (UnmanagedType.LPStr)] String owner, [MarshalAs (UnmanagedType.LPStr)] String name, Single value); + #else // !USE_LIBRARY_IMPORT + [DllImport (SKIA, CallingConvention = CallingConvention.Cdecl)] + internal static extern void sk_pdf_structure_element_add_float_attribute (sk_pdf_structure_element_t element, [MarshalAs (UnmanagedType.LPStr)] String owner, [MarshalAs (UnmanagedType.LPStr)] String name, Single value); + #endif + #else + private partial class Delegates { + [UnmanagedFunctionPointer (CallingConvention.Cdecl)] + internal delegate void sk_pdf_structure_element_add_float_attribute (sk_pdf_structure_element_t element, [MarshalAs (UnmanagedType.LPStr)] String owner, [MarshalAs (UnmanagedType.LPStr)] String name, Single value); + } + private static Delegates.sk_pdf_structure_element_add_float_attribute sk_pdf_structure_element_add_float_attribute_delegate; + internal static void sk_pdf_structure_element_add_float_attribute (sk_pdf_structure_element_t element, [MarshalAs (UnmanagedType.LPStr)] String owner, [MarshalAs (UnmanagedType.LPStr)] String name, Single value) => + (sk_pdf_structure_element_add_float_attribute_delegate ??= GetSymbol ("sk_pdf_structure_element_add_float_attribute")).Invoke (element, owner, name, value); + #endif + + // void sk_pdf_structure_element_add_int_attribute(sk_pdf_structure_element_t* element, const char* owner, const char* name, int value) + #if !USE_DELEGATES + #if USE_LIBRARY_IMPORT + [LibraryImport (SKIA)] + internal static partial void sk_pdf_structure_element_add_int_attribute (sk_pdf_structure_element_t element, [MarshalAs (UnmanagedType.LPStr)] String owner, [MarshalAs (UnmanagedType.LPStr)] String name, Int32 value); + #else // !USE_LIBRARY_IMPORT + [DllImport (SKIA, CallingConvention = CallingConvention.Cdecl)] + internal static extern void sk_pdf_structure_element_add_int_attribute (sk_pdf_structure_element_t element, [MarshalAs (UnmanagedType.LPStr)] String owner, [MarshalAs (UnmanagedType.LPStr)] String name, Int32 value); + #endif + #else + private partial class Delegates { + [UnmanagedFunctionPointer (CallingConvention.Cdecl)] + internal delegate void sk_pdf_structure_element_add_int_attribute (sk_pdf_structure_element_t element, [MarshalAs (UnmanagedType.LPStr)] String owner, [MarshalAs (UnmanagedType.LPStr)] String name, Int32 value); + } + private static Delegates.sk_pdf_structure_element_add_int_attribute sk_pdf_structure_element_add_int_attribute_delegate; + internal static void sk_pdf_structure_element_add_int_attribute (sk_pdf_structure_element_t element, [MarshalAs (UnmanagedType.LPStr)] String owner, [MarshalAs (UnmanagedType.LPStr)] String name, Int32 value) => + (sk_pdf_structure_element_add_int_attribute_delegate ??= GetSymbol ("sk_pdf_structure_element_add_int_attribute")).Invoke (element, owner, name, value); + #endif + + // void sk_pdf_structure_element_add_name_attribute(sk_pdf_structure_element_t* element, const char* owner, const char* name, const char* value) + #if !USE_DELEGATES + #if USE_LIBRARY_IMPORT + [LibraryImport (SKIA)] + internal static partial void sk_pdf_structure_element_add_name_attribute (sk_pdf_structure_element_t element, [MarshalAs (UnmanagedType.LPStr)] String owner, [MarshalAs (UnmanagedType.LPStr)] String name, [MarshalAs (UnmanagedType.LPStr)] String value); + #else // !USE_LIBRARY_IMPORT + [DllImport (SKIA, CallingConvention = CallingConvention.Cdecl)] + internal static extern void sk_pdf_structure_element_add_name_attribute (sk_pdf_structure_element_t element, [MarshalAs (UnmanagedType.LPStr)] String owner, [MarshalAs (UnmanagedType.LPStr)] String name, [MarshalAs (UnmanagedType.LPStr)] String value); + #endif + #else + private partial class Delegates { + [UnmanagedFunctionPointer (CallingConvention.Cdecl)] + internal delegate void sk_pdf_structure_element_add_name_attribute (sk_pdf_structure_element_t element, [MarshalAs (UnmanagedType.LPStr)] String owner, [MarshalAs (UnmanagedType.LPStr)] String name, [MarshalAs (UnmanagedType.LPStr)] String value); + } + private static Delegates.sk_pdf_structure_element_add_name_attribute sk_pdf_structure_element_add_name_attribute_delegate; + internal static void sk_pdf_structure_element_add_name_attribute (sk_pdf_structure_element_t element, [MarshalAs (UnmanagedType.LPStr)] String owner, [MarshalAs (UnmanagedType.LPStr)] String name, [MarshalAs (UnmanagedType.LPStr)] String value) => + (sk_pdf_structure_element_add_name_attribute_delegate ??= GetSymbol ("sk_pdf_structure_element_add_name_attribute")).Invoke (element, owner, name, value); + #endif + + // void sk_pdf_structure_element_add_node_id_array_attribute(sk_pdf_structure_element_t* element, const char* owner, const char* name, int* values, size_t count) + #if !USE_DELEGATES + #if USE_LIBRARY_IMPORT + [LibraryImport (SKIA)] + internal static partial void sk_pdf_structure_element_add_node_id_array_attribute (sk_pdf_structure_element_t element, [MarshalAs (UnmanagedType.LPStr)] String owner, [MarshalAs (UnmanagedType.LPStr)] String name, Int32* values, /* size_t */ IntPtr count); + #else // !USE_LIBRARY_IMPORT + [DllImport (SKIA, CallingConvention = CallingConvention.Cdecl)] + internal static extern void sk_pdf_structure_element_add_node_id_array_attribute (sk_pdf_structure_element_t element, [MarshalAs (UnmanagedType.LPStr)] String owner, [MarshalAs (UnmanagedType.LPStr)] String name, Int32* values, /* size_t */ IntPtr count); + #endif + #else + private partial class Delegates { + [UnmanagedFunctionPointer (CallingConvention.Cdecl)] + internal delegate void sk_pdf_structure_element_add_node_id_array_attribute (sk_pdf_structure_element_t element, [MarshalAs (UnmanagedType.LPStr)] String owner, [MarshalAs (UnmanagedType.LPStr)] String name, Int32* values, /* size_t */ IntPtr count); + } + private static Delegates.sk_pdf_structure_element_add_node_id_array_attribute sk_pdf_structure_element_add_node_id_array_attribute_delegate; + internal static void sk_pdf_structure_element_add_node_id_array_attribute (sk_pdf_structure_element_t element, [MarshalAs (UnmanagedType.LPStr)] String owner, [MarshalAs (UnmanagedType.LPStr)] String name, Int32* values, /* size_t */ IntPtr count) => + (sk_pdf_structure_element_add_node_id_array_attribute_delegate ??= GetSymbol ("sk_pdf_structure_element_add_node_id_array_attribute")).Invoke (element, owner, name, values, count); + #endif + + // void sk_pdf_structure_element_delete(sk_pdf_structure_element_t* element) + #if !USE_DELEGATES + #if USE_LIBRARY_IMPORT + [LibraryImport (SKIA)] + internal static partial void sk_pdf_structure_element_delete (sk_pdf_structure_element_t element); + #else // !USE_LIBRARY_IMPORT + [DllImport (SKIA, CallingConvention = CallingConvention.Cdecl)] + internal static extern void sk_pdf_structure_element_delete (sk_pdf_structure_element_t element); + #endif + #else + private partial class Delegates { + [UnmanagedFunctionPointer (CallingConvention.Cdecl)] + internal delegate void sk_pdf_structure_element_delete (sk_pdf_structure_element_t element); + } + private static Delegates.sk_pdf_structure_element_delete sk_pdf_structure_element_delete_delegate; + internal static void sk_pdf_structure_element_delete (sk_pdf_structure_element_t element) => + (sk_pdf_structure_element_delete_delegate ??= GetSymbol ("sk_pdf_structure_element_delete")).Invoke (element); + #endif + + // sk_pdf_structure_element_t* sk_pdf_structure_element_new() + #if !USE_DELEGATES + #if USE_LIBRARY_IMPORT + [LibraryImport (SKIA)] + internal static partial sk_pdf_structure_element_t sk_pdf_structure_element_new (); + #else // !USE_LIBRARY_IMPORT + [DllImport (SKIA, CallingConvention = CallingConvention.Cdecl)] + internal static extern sk_pdf_structure_element_t sk_pdf_structure_element_new (); + #endif + #else + private partial class Delegates { + [UnmanagedFunctionPointer (CallingConvention.Cdecl)] + internal delegate sk_pdf_structure_element_t sk_pdf_structure_element_new (); + } + private static Delegates.sk_pdf_structure_element_new sk_pdf_structure_element_new_delegate; + internal static sk_pdf_structure_element_t sk_pdf_structure_element_new () => + (sk_pdf_structure_element_new_delegate ??= GetSymbol ("sk_pdf_structure_element_new")).Invoke (); + #endif + + // void sk_pdf_structure_element_set_alt(sk_pdf_structure_element_t* element, sk_string_t* value) + #if !USE_DELEGATES + #if USE_LIBRARY_IMPORT + [LibraryImport (SKIA)] + internal static partial void sk_pdf_structure_element_set_alt (sk_pdf_structure_element_t element, sk_string_t value); + #else // !USE_LIBRARY_IMPORT + [DllImport (SKIA, CallingConvention = CallingConvention.Cdecl)] + internal static extern void sk_pdf_structure_element_set_alt (sk_pdf_structure_element_t element, sk_string_t value); + #endif + #else + private partial class Delegates { + [UnmanagedFunctionPointer (CallingConvention.Cdecl)] + internal delegate void sk_pdf_structure_element_set_alt (sk_pdf_structure_element_t element, sk_string_t value); + } + private static Delegates.sk_pdf_structure_element_set_alt sk_pdf_structure_element_set_alt_delegate; + internal static void sk_pdf_structure_element_set_alt (sk_pdf_structure_element_t element, sk_string_t value) => + (sk_pdf_structure_element_set_alt_delegate ??= GetSymbol ("sk_pdf_structure_element_set_alt")).Invoke (element, value); + #endif + + // void sk_pdf_structure_element_set_lang(sk_pdf_structure_element_t* element, sk_string_t* value) + #if !USE_DELEGATES + #if USE_LIBRARY_IMPORT + [LibraryImport (SKIA)] + internal static partial void sk_pdf_structure_element_set_lang (sk_pdf_structure_element_t element, sk_string_t value); + #else // !USE_LIBRARY_IMPORT + [DllImport (SKIA, CallingConvention = CallingConvention.Cdecl)] + internal static extern void sk_pdf_structure_element_set_lang (sk_pdf_structure_element_t element, sk_string_t value); + #endif + #else + private partial class Delegates { + [UnmanagedFunctionPointer (CallingConvention.Cdecl)] + internal delegate void sk_pdf_structure_element_set_lang (sk_pdf_structure_element_t element, sk_string_t value); + } + private static Delegates.sk_pdf_structure_element_set_lang sk_pdf_structure_element_set_lang_delegate; + internal static void sk_pdf_structure_element_set_lang (sk_pdf_structure_element_t element, sk_string_t value) => + (sk_pdf_structure_element_set_lang_delegate ??= GetSymbol ("sk_pdf_structure_element_set_lang")).Invoke (element, value); + #endif + + // void sk_pdf_structure_element_set_node_id(sk_pdf_structure_element_t* element, int value) + #if !USE_DELEGATES + #if USE_LIBRARY_IMPORT + [LibraryImport (SKIA)] + internal static partial void sk_pdf_structure_element_set_node_id (sk_pdf_structure_element_t element, Int32 value); + #else // !USE_LIBRARY_IMPORT + [DllImport (SKIA, CallingConvention = CallingConvention.Cdecl)] + internal static extern void sk_pdf_structure_element_set_node_id (sk_pdf_structure_element_t element, Int32 value); + #endif + #else + private partial class Delegates { + [UnmanagedFunctionPointer (CallingConvention.Cdecl)] + internal delegate void sk_pdf_structure_element_set_node_id (sk_pdf_structure_element_t element, Int32 value); + } + private static Delegates.sk_pdf_structure_element_set_node_id sk_pdf_structure_element_set_node_id_delegate; + internal static void sk_pdf_structure_element_set_node_id (sk_pdf_structure_element_t element, Int32 value) => + (sk_pdf_structure_element_set_node_id_delegate ??= GetSymbol ("sk_pdf_structure_element_set_node_id")).Invoke (element, value); + #endif + + // void sk_pdf_structure_element_set_type_string(sk_pdf_structure_element_t* element, sk_string_t* value) + #if !USE_DELEGATES + #if USE_LIBRARY_IMPORT + [LibraryImport (SKIA)] + internal static partial void sk_pdf_structure_element_set_type_string (sk_pdf_structure_element_t element, sk_string_t value); + #else // !USE_LIBRARY_IMPORT + [DllImport (SKIA, CallingConvention = CallingConvention.Cdecl)] + internal static extern void sk_pdf_structure_element_set_type_string (sk_pdf_structure_element_t element, sk_string_t value); + #endif + #else + private partial class Delegates { + [UnmanagedFunctionPointer (CallingConvention.Cdecl)] + internal delegate void sk_pdf_structure_element_set_type_string (sk_pdf_structure_element_t element, sk_string_t value); + } + private static Delegates.sk_pdf_structure_element_set_type_string sk_pdf_structure_element_set_type_string_delegate; + internal static void sk_pdf_structure_element_set_type_string (sk_pdf_structure_element_t element, sk_string_t value) => + (sk_pdf_structure_element_set_type_string_delegate ??= GetSymbol ("sk_pdf_structure_element_set_type_string")).Invoke (element, value); + #endif + #endregion #region sk_drawable.h @@ -18373,75 +18945,6 @@ public readonly override int GetHashCode () } - // sk_document_pdf_metadata_t - [StructLayout (LayoutKind.Sequential)] - internal unsafe partial struct SKDocumentPdfMetadataInternal : IEquatable { - // public sk_string_t* fTitle - public sk_string_t fTitle; - - // public sk_string_t* fAuthor - public sk_string_t fAuthor; - - // public sk_string_t* fSubject - public sk_string_t fSubject; - - // public sk_string_t* fKeywords - public sk_string_t fKeywords; - - // public sk_string_t* fCreator - public sk_string_t fCreator; - - // public sk_string_t* fProducer - public sk_string_t fProducer; - - // public sk_time_datetime_t* fCreation - public SKTimeDateTimeInternal* fCreation; - - // public sk_time_datetime_t* fModified - public SKTimeDateTimeInternal* fModified; - - // public float fRasterDPI - public Single fRasterDPI; - - // public bool fPDFA - public Byte fPDFA; - - // public int fEncodingQuality - public Int32 fEncodingQuality; - - public readonly bool Equals (SKDocumentPdfMetadataInternal obj) => -#pragma warning disable CS8909 - fTitle == obj.fTitle && fAuthor == obj.fAuthor && fSubject == obj.fSubject && fKeywords == obj.fKeywords && fCreator == obj.fCreator && fProducer == obj.fProducer && fCreation == obj.fCreation && fModified == obj.fModified && fRasterDPI == obj.fRasterDPI && fPDFA == obj.fPDFA && fEncodingQuality == obj.fEncodingQuality; -#pragma warning restore CS8909 - - public readonly override bool Equals (object obj) => - obj is SKDocumentPdfMetadataInternal f && Equals (f); - - public static bool operator == (SKDocumentPdfMetadataInternal left, SKDocumentPdfMetadataInternal right) => - left.Equals (right); - - public static bool operator != (SKDocumentPdfMetadataInternal left, SKDocumentPdfMetadataInternal right) => - !left.Equals (right); - - public readonly override int GetHashCode () - { - var hash = new HashCode (); - hash.Add (fTitle); - hash.Add (fAuthor); - hash.Add (fSubject); - hash.Add (fKeywords); - hash.Add (fCreator); - hash.Add (fProducer); - hash.Add (fCreation); - hash.Add (fModified); - hash.Add (fRasterDPI); - hash.Add (fPDFA); - hash.Add (fEncodingQuality); - return hash.ToHashCode (); - } - - } - // sk_fontmetrics_t [StructLayout (LayoutKind.Sequential)] public unsafe partial struct SKFontMetrics : IEquatable { @@ -20501,6 +21004,20 @@ public enum SKPathOp { ReverseDifference = 4, } + // sk_pdf_compression_t + public enum SKPdfCompression { + // DEFAULT_SK_PDF_COMPRESSION = -1 + Default = -1, + // NONE_SK_PDF_COMPRESSION = 0 + None = 0, + // LOW_SK_PDF_COMPRESSION = 1 + Low = 1, + // AVERAGE_SK_PDF_COMPRESSION = 6 + Average = 6, + // HIGH_SK_PDF_COMPRESSION = 9 + High = 9, + } + // sk_pixelgeometry_t public enum SKPixelGeometry { // UNKNOWN_SK_PIXELGEOMETRY = 0 diff --git a/binding/SkiaSharp/Util.cs b/binding/SkiaSharp/Util.cs index 3846d58dcb..f5ed1a7fa4 100644 --- a/binding/SkiaSharp/Util.cs +++ b/binding/SkiaSharp/Util.cs @@ -2,6 +2,7 @@ using System; using System.Buffers; +using System.Collections.Generic; using System.ComponentModel; using System.Text; #if NETSTANDARD1_3 || WINDOWS_UWP @@ -60,6 +61,16 @@ internal static byte[] GetBytes (this Encoding encoding, ReadOnlySpan text } } +#if NET45_OR_GREATER || NETSTANDARD2_0 + public static int GetBytes (this Encoding encoding, ReadOnlySpan text, Span bytes) + { + fixed (char* t = text) + fixed (byte* b = bytes) { + return encoding.GetBytes (t, text.Length, b, bytes.Length); + } + } +#endif + public static RentedArray RentArray (int length, bool nullIfEmpty = false) => nullIfEmpty && length <= 0 ? default @@ -74,6 +85,15 @@ public static RentedArray RentHandlesArray (SKObject[] objects, bool nul return handles; } + public static RentedArray ToRentedArray (IList list) + { + var rented = new RentedArray (list.Count); + for (var idx = 0; idx < list.Count; idx++) { + rented[idx] = list[idx]; + } + return rented; + } + internal readonly ref struct RentedArray { internal RentedArray (int length) @@ -177,6 +197,24 @@ public static byte[] GetEncodedText (ReadOnlySpan text, SKTextEncoding enc _ => throw new ArgumentOutOfRangeException (nameof (encoding), $"Encoding {encoding} is not supported."), }; + public static int GetEncodedText (ReadOnlySpan text, Span bytes, SKTextEncoding encoding) => + encoding switch { + SKTextEncoding.Utf8 => Encoding.UTF8.GetBytes (text, bytes), + SKTextEncoding.Utf16 => Encoding.Unicode.GetBytes (text, bytes), + SKTextEncoding.Utf32 => Encoding.UTF32.GetBytes (text, bytes), + _ => throw new ArgumentOutOfRangeException (nameof (encoding), $"Encoding {encoding} is not supported."), + }; + + // GetMaxByteCount + + public static int GetMaxByteCount (ReadOnlySpan text, SKTextEncoding encoding) => + encoding switch { + SKTextEncoding.Utf8 => Encoding.UTF8.GetMaxByteCount (text.Length), + SKTextEncoding.Utf16 => Encoding.Unicode.GetMaxByteCount (text.Length), + SKTextEncoding.Utf32 => Encoding.UTF32.GetMaxByteCount (text.Length), + _ => throw new ArgumentOutOfRangeException (nameof (encoding), $"Encoding {encoding} is not supported."), + }; + // GetString public static string GetString (IntPtr data, int dataLength, SKTextEncoding encoding) => diff --git a/binding/libSkiaSharp.json b/binding/libSkiaSharp.json index adeb369440..df4f90ccf1 100644 --- a/binding/libSkiaSharp.json +++ b/binding/libSkiaSharp.json @@ -373,8 +373,20 @@ "cs": "SKCodecOptionsInternal", "internal": true }, - "sk_document_pdf_metadata_t": { - "cs": "SKDocumentPdfMetadataInternal", + "sk_pdf_metadata_t": { + "cs": "SKPdfMetadataInternal", + "internal": true + }, + "sk_pdf_attribute_item_type_t": { + "cs": "SKPdfAttributeItemTypeInternal", + "internal": true + }, + "sk_pdf_attribute_item_t": { + "cs": "SKPdfAttributeItemInternal", + "internal": true + }, + "sk_pdf_structure_element_t": { + "cs": "SKPdfStructureElementInternal", "internal": true }, "sk_lattice_t": { @@ -484,6 +496,37 @@ "1": "[MarshalAs (UnmanagedType.LPStr)] String" } }, + "sk_pdf_structure_element_add_int_attribute": { + "parameters": { + "1": "[MarshalAs (UnmanagedType.LPStr)] String", + "2": "[MarshalAs (UnmanagedType.LPStr)] String" + } + }, + "sk_pdf_structure_element_add_float_attribute": { + "parameters": { + "1": "[MarshalAs (UnmanagedType.LPStr)] String", + "2": "[MarshalAs (UnmanagedType.LPStr)] String" + } + }, + "sk_pdf_structure_element_add_name_attribute": { + "parameters": { + "1": "[MarshalAs (UnmanagedType.LPStr)] String", + "2": "[MarshalAs (UnmanagedType.LPStr)] String", + "3": "[MarshalAs (UnmanagedType.LPStr)] String" + } + }, + "sk_pdf_structure_element_add_node_id_array_attribute": { + "parameters": { + "1": "[MarshalAs (UnmanagedType.LPStr)] String", + "2": "[MarshalAs (UnmanagedType.LPStr)] String" + } + }, + "sk_pdf_structure_element_add_float_array_attribute": { + "parameters": { + "1": "[MarshalAs (UnmanagedType.LPStr)] String", + "2": "[MarshalAs (UnmanagedType.LPStr)] String" + } + }, "sk_image_raster_release_proc": { "proxySuffixes": [ "", "ForCoTaskMem" diff --git a/externals/skia b/externals/skia index 8521cbb949..3b1ee48e07 160000 --- a/externals/skia +++ b/externals/skia @@ -1 +1 @@ -Subproject commit 8521cbb9493fbb162f7b0bab720ee5a5021390ba +Subproject commit 3b1ee48e07c201d796e57182c66ce09c795b013f diff --git a/tests/Tests/SkiaSharp/SKDocumentTest.cs b/tests/Tests/SkiaSharp/SKDocumentTest.cs index 717fb03ac6..3b5f3425fd 100644 --- a/tests/Tests/SkiaSharp/SKDocumentTest.cs +++ b/tests/Tests/SkiaSharp/SKDocumentTest.cs @@ -81,12 +81,40 @@ public void CanCreatePdf() } } + [Obsolete] [SkippableFact] - public void CanCreatePdfWithMetadata() + public void CanCreatePdfWithObsoleteMetadata() { var metadata = SKDocumentPdfMetadata.Default; metadata.Author = "SkiaSharp Team"; + using var stream = new MemoryStream(); + using (var doc = SKDocument.CreatePdf(stream, metadata)) + { + Assert.NotNull(doc); + Assert.NotNull(doc.BeginPage(100, 100)); + + doc.EndPage(); + doc.Close(); + } + + Assert.True(stream.Length > 0); + Assert.True(stream.Position > 0); + + stream.Position = 0; + using var reader = new StreamReader(stream); + var contents = reader.ReadToEnd(); + Assert.Contains("/Author (SkiaSharp Team)", contents); + } + + [SkippableFact] + public void CanCreatePdfWithMetadata() + { + var metadata = new SKPdfMetadata + { + Author = "SkiaSharp Team" + }; + using (var stream = new MemoryStream()) { using (var doc = SKDocument.CreatePdf(stream, metadata)) @@ -167,7 +195,6 @@ public void CanCreateXps() } } - [SkippableFact] public void StreamIsNotCollectedPrematurely() { @@ -201,8 +228,377 @@ static SKDocument CreateDocument(out IntPtr streamHandle) var stream = new SKDynamicMemoryWStream(); streamHandle = stream.Handle; - return SKDocument.CreatePdf(stream, new SKDocumentPdfMetadata()); + return SKDocument.CreatePdf(stream, new SKPdfMetadata()); } } + + [SkippableFact] + public void MetadataIsAddedToFile() + { + var now = DateTime.Now; + var metadata = new SKPdfMetadata + { + Title = "A1", + Author = "A2", + Subject = "A3", + Keywords = "A4", + Creator = "A5", + Creation = now, + Modified = now, + }; + + var expectations = new string[] { + "/Title (A1)", + "/Author (A2)", + "/Subject (A3)", + "/Keywords (A4)", + "/Creator (A5)", + "/Producer (Skia/PDF ", + "/CreationDate (D:", + "/ModDate (D:" + }; + + AssertPdfMetadata(metadata, expectations); + } + + [SkippableFact] + public void PdfAMetadataIsAddedToFile() + { + var metadata = new SKPdfMetadata + { + Title = "test document", + Creation = new DateTime(1999, 12, 31, 23, 59, 59, DateTimeKind.Utc), + PdfA = true, + Producer = "phoney library" + }; + + var expectations = new string[] { + "sRGB IEC61966-2.1", + "test document", + "1999-12-31T23:59:59+00:00", + "/Subtype /XML", + "/CreationDate (D:19991231235959+00'00')>>", + "/Producer (phoney library)", + "phoney library", + }; + + AssertPdfMetadata(metadata, expectations); + } + + [SkippableFact] + public void UnicodeMetadataIsAddedToFile() + { + var metadata = new SKPdfMetadata + { + PdfA = true, + Title = "𝓐𝓑𝓒𝓓𝓔 𝓕𝓖𝓗𝓘𝓙", // Out of basic multilingual plane + Author = "ABCDE FGHIJ", // ASCII + Subject = "αβγδε ζηθικ", // inside basic multilingual plane + }; + + var expectations = new string[] { + "<", + "/Author (ABCDE FGHIJ)", + "Subject ", + }; + + AssertPdfMetadata(metadata, expectations); + } + + [SkippableTheory] + [InlineData(1)] + [InlineData(2)] + [InlineData(100)] + public void MultiplePagesWorkCorrectly(int pageCount) + { + var pdfData = GeneratePdf(new(), doc => + { + for (var i = 0; i < pageCount; ++i) + { + var cnv = doc.BeginPage(612, 792); + var color = new SKColor(0x00, (byte)(255.0f * i / (pageCount - 1)), 0x00); + cnv.DrawColor(color); + } + }); + + var pagesString = $"< 0); + Assert.True(stream.Position > 0); + } + + [SkippableFact] + public void CanCreateTaggedLinkPdfWithConstructorStructures() + { + var metadata = new SKPdfMetadata + { + Title = "Example Tagged PDF With Links", + Creator = "Skia", + Creation = DateTime.Now, + Modified = DateTime.Now, + // The document tag. + Structure = new SKPdfStructureElementNode(1, "Document") + { + Language = "en-US", + Children = + { + // A link. + new SKPdfStructureElementNode(2, "Link") + } + } + }; + + using var stream = new MemoryStream(); + using (var doc = SKDocument.CreatePdf(stream, metadata)) + { + Assert.NotNull(doc); + + var canvas = doc.BeginPage(612, 792); // U.S. Letter + Assert.NotNull(canvas); + + var paint = new SKPaint(); + paint.Color = SKColors.Blue; + + var font = new SKFont(); + font.Size = 20; + + // The node ID should cover both the text and the annotation. + canvas.DrawPdfNodeAnnotation(2); + canvas.DrawText("Click to visit Google.com", 72, 72, font, paint); + var linkRect = SKRect.Create(72, 54, 218, 24); + canvas.DrawUrlAnnotation(linkRect, "http://www.google.com"); + + doc.EndPage(); + doc.Close(); + } + + Assert.True(stream.Length > 0); + Assert.True(stream.Position > 0); + } + + [SkippableFact] + public void CanCreateTaggedPdf() + { + var pageSize = new SKSize(612, 792); // U.S. Letter + + var metadata = new SKPdfMetadata(); + metadata.Title = "Example Tagged PDF"; + metadata.Creator = "Skia"; + var now = DateTime.Now; + metadata.Creation = now; + metadata.Modified = now; + + // The document tag. + var root = new SKPdfStructureElementNode(1, "Document"); + + // Heading. + var h1 = new SKPdfStructureElementNode(2, "H1"); + root.Children.Add(h1); + + // Initial paragraph. + var p = new SKPdfStructureElementNode(3, "P"); + root.Children.Add(p); + + // Hidden div. This is never referenced by marked content + // so it should not appear in the resulting PDF. + var div = new SKPdfStructureElementNode(4, "Div"); + root.Children.Add(div); + + // A bulleted list of two items. + var l = new SKPdfStructureElementNode(5, "L"); + + var lm1 = new SKPdfStructureElementNode(6, "Lbl"); + l.Children.Add(lm1); + + var li1 = new SKPdfStructureElementNode(7, "LI"); + l.Children.Add(li1); + + var lm2 = new SKPdfStructureElementNode(8, "Lbl"); + l.Children.Add(lm2); + + var li2 = new SKPdfStructureElementNode(9, "LI"); + l.Children.Add(li2); + + root.Children.Add(l); + + // Paragraph spanning two pages. + var p2 = new SKPdfStructureElementNode(10, "P"); + root.Children.Add(p2); + + // Image with alt text. + var img = new SKPdfStructureElementNode(11, "Figure"); + img.Alt = "Red box"; + root.Children.Add(img); + + metadata.Structure = root; + + var outputStream = new MemoryStream(); + var document = SKDocument.CreatePdf(outputStream, metadata); + + var paint = new SKPaint(); + paint.Color = SKColors.Black; + + // First page. + { + var canvas = document.BeginPage(pageSize.Width, pageSize.Height); + + canvas.DrawPdfNodeAnnotation(2); + var font = new SKFont(null, 36); + var message = "This is the title"; + canvas.Translate(72, 72); + canvas.DrawText(message, 0, 0, font, paint); + + canvas.DrawPdfNodeAnnotation(3); + font.Size = 14; + message = "This is a simple paragraph."; + canvas.Translate(0, 72); + canvas.DrawText(message, 0, 0, font, paint); + + canvas.DrawPdfNodeAnnotation(6); + message = "*"; + canvas.Translate(0, 72); + canvas.DrawText(message, 0, 0, font, paint); + + canvas.DrawPdfNodeAnnotation(7); + message = "List item 1"; + canvas.Translate(36, 0); + canvas.DrawText(message, 0, 0, font, paint); + + canvas.DrawPdfNodeAnnotation(8); + message = "*"; + canvas.Translate(-36, 36); + canvas.DrawText(message, 0, 0, font, paint); + + canvas.DrawPdfNodeAnnotation(9); + message = "List item 2"; + canvas.Translate(36, 0); + canvas.DrawText(message, 0, 0, font, paint); + + canvas.DrawPdfNodeAnnotation(10); + message = "This is a paragraph that starts on one page"; + canvas.Translate(-36, 6 * 72); + canvas.DrawText(message, 0, 0, font, paint); + + document.EndPage(); + } + + // Second page. + { + var canvas = document.BeginPage(pageSize.Width, pageSize.Height); + + canvas.DrawPdfNodeAnnotation(10); + var font = new SKFont(null, 14); + var message = "and finishes on the second page."; + canvas.Translate(72, 72); + canvas.DrawText(message, 0, 0, font, paint); + + // Test a tagged image with alt text. + canvas.DrawPdfNodeAnnotation(11); + var testBitmap = new SKBitmap(new SKImageInfo(72, 72)); + testBitmap.Erase(SKColors.Red); + canvas.Translate(72, 72); + canvas.DrawImage(testBitmap.ToImage(), 0, 0); + + // This has a node ID but never shows up in the tag tree so it + // won't be tagged. + canvas.DrawPdfNodeAnnotation(999); + message = "Page 2"; + canvas.Translate(468, -36); + canvas.DrawText(message, 0, 0, font, paint); + + document.EndPage(); + } + + document.Close(); + } + + private static void AssertPdfMetadata(SKPdfMetadata metadata, params string[] expectations) + { + var pdfData = GeneratePdf(metadata); + + foreach (var expectation in expectations) + { + Assert.Contains(expectation, pdfData); + } + } + + private static string GeneratePdf(SKPdfMetadata metadata, Action generate = null) + { + using var stream = new MemoryStream(); + using (var doc = SKDocument.CreatePdf(stream, metadata)) + { + Assert.NotNull(doc); + + if (generate is not null) + { + generate.Invoke(doc); + } + else + { + var canvas = doc.BeginPage(612.0f, 792.0f); + Assert.NotNull(canvas); + + canvas.DrawColor(SKColors.Red); + + doc.Close(); + } + } + + Assert.True(stream.Length > 0); + Assert.True(stream.Position > 0); + + stream.Position = 0; + + using var reader = new StreamReader(stream); + var data = reader.ReadToEnd(); + + return data; + } } } diff --git a/tests/Tests/SkiaSharp/SKTest.cs b/tests/Tests/SkiaSharp/SKTest.cs index 05dbcafae5..a5243212ef 100644 --- a/tests/Tests/SkiaSharp/SKTest.cs +++ b/tests/Tests/SkiaSharp/SKTest.cs @@ -53,6 +53,14 @@ protected static SKStreamAsset CreateTestSKStream(int length = 1024) return new SKMemoryStream(bytes); } + protected static void SaveStream(Stream stream, string filename) + { + stream.Position = 0; + + using var file = File.Create(Path.Combine(PathToImages, filename)); + stream.CopyTo(file); + } + protected static void SaveSurface(SKSurface surface, string filename = "output.png") { using var image = surface.Snapshot();