diff --git a/binding/Binding/Definitions.cs b/binding/Binding/Definitions.cs index 9c5badaf..5be4dca7 100644 --- a/binding/Binding/Definitions.cs +++ b/binding/Binding/Definitions.cs @@ -554,9 +554,71 @@ namespace SkiaSharp public sk_string_t Producer; public SKTimeDateTimeInternal* Creation; public SKTimeDateTimeInternal* Modified; + public float RasterDPI; + public byte PDFA; + public int EncodingQuality; } public struct SKDocumentPdfMetadata { + public const float DefaultRasterDpi = 72.0f; + public const int DefaultEncodingQuality = 101; + + public static readonly SKDocumentPdfMetadata Default; + + static SKDocumentPdfMetadata () + { + Default = new SKDocumentPdfMetadata () { + RasterDpi = DefaultRasterDpi, + PdfA = false, + EncodingQuality = 101, + }; + } + + public SKDocumentPdfMetadata (float rasterDpi) + { + Title = null; + Author = null; + Subject = null; + Keywords = null; + Creator = null; + Producer = null; + Creation = null; + Modified = null; + RasterDpi = rasterDpi; + PdfA = false; + EncodingQuality = DefaultEncodingQuality; + } + + public SKDocumentPdfMetadata (int encodingQuality) + { + Title = null; + Author = null; + Subject = null; + Keywords = null; + Creator = null; + Producer = null; + Creation = null; + Modified = null; + RasterDpi = DefaultRasterDpi; + PdfA = false; + EncodingQuality = encodingQuality; + } + + public SKDocumentPdfMetadata (float rasterDpi, int encodingQuality) + { + Title = null; + Author = null; + Subject = null; + Keywords = null; + Creator = null; + Producer = null; + Creation = null; + Modified = null; + RasterDpi = rasterDpi; + PdfA = false; + EncodingQuality = encodingQuality; + } + public string Title { get; set; } public string Author { get; set; } public string Subject { get; set; } @@ -565,6 +627,9 @@ namespace SkiaSharp public string Producer { get; set; } public DateTime? Creation { get; set; } public DateTime? Modified { get; set; } + public float RasterDpi { get; set; } + public bool PdfA { get; set; } + public int EncodingQuality { get; set; } } public enum SKColorSpaceGamut { diff --git a/binding/Binding/SKDocument.cs b/binding/Binding/SKDocument.cs index 2d8f6a07..f9687d28 100644 --- a/binding/Binding/SKDocument.cs +++ b/binding/Binding/SKDocument.cs @@ -1,13 +1,14 @@ using System; +using System.IO; namespace SkiaSharp { public class SKDocument : SKObject { - public const float DefaultRasterDpi = 72.0f; + public const float DefaultRasterDpi = SKDocumentPdfMetadata.DefaultRasterDpi; [Preserve] - internal SKDocument(IntPtr handle, bool owns) + internal SKDocument (IntPtr handle, bool owns) : base (handle, owns) { } @@ -21,97 +22,132 @@ namespace SkiaSharp base.Dispose (disposing); } - public void Abort () - { + public void Abort () => SkiaApi.sk_document_abort (Handle); - } - public SKCanvas BeginPage (float width, float height) - { - return GetObject (SkiaApi.sk_document_begin_page (Handle, width, height, IntPtr.Zero), false); - } + public SKCanvas BeginPage (float width, float height) => + GetObject (SkiaApi.sk_document_begin_page (Handle, width, height, IntPtr.Zero), false); - public SKCanvas BeginPage (float width, float height, SKRect content) - { - return GetObject (SkiaApi.sk_document_begin_page (Handle, width, height, ref content), false); - } + public SKCanvas BeginPage (float width, float height, SKRect content) => + GetObject (SkiaApi.sk_document_begin_page (Handle, width, height, ref content), false); - public void EndPage () - { + public void EndPage () => SkiaApi.sk_document_end_page (Handle); - } - public void Close () - { + public void Close () => SkiaApi.sk_document_close (Handle); - } - [Obsolete ("Use CreateXps(SKWStream, float) instead.")] - public static SKDocument CreateXps (string path, float dpi = DefaultRasterDpi) + // CreateXps + + public static SKDocument CreateXps (string path) => + CreateXps (path, DefaultRasterDpi); + + public static SKDocument CreateXps (Stream 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)); } var stream = SKFileWStream.OpenStream (path); - var doc = CreateXps (stream, dpi); - if (doc != null) - doc.SetDisposeChild (stream); - else - stream.Dispose(); - return doc; + return Owned (CreateXps (stream, dpi), stream); } - public static SKDocument CreateXps (SKWStream stream, float dpi = DefaultRasterDpi) + public static SKDocument CreateXps (Stream stream, float dpi) { if (stream == null) { - throw new ArgumentNullException (nameof(stream)); + throw new ArgumentNullException (nameof (stream)); + } + + 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)); } return GetObject (SkiaApi.sk_document_create_xps_from_stream (stream.Handle, dpi)); } - [Obsolete ("Use CreatePdf(SKWStream) instead.")] - public static SKDocument CreatePdf (string path, float dpi = DefaultRasterDpi) + // CreatePdf + + [Obsolete ("Use CreatePdf(SKWStream, SKDocumentPdfMetadata) instead.")] + public static SKDocument CreatePdf (SKWStream stream, SKDocumentPdfMetadata metadata, float dpi) + { + metadata.RasterDpi = dpi; + return CreatePdf (stream, metadata); + } + + public static SKDocument CreatePdf (string path) { if (path == null) { throw new ArgumentNullException (nameof (path)); } var stream = SKFileWStream.OpenStream (path); - var doc = CreatePdf (stream, dpi); - if (doc != null) - doc.SetDisposeChild (stream); - else - stream.Dispose(); - return doc; + return Owned (CreatePdf (stream), stream); } - [Obsolete("Use CreatePdf(SKWStream) instead.")] - public static SKDocument CreatePdf (SKWStream stream, float dpi) + public static SKDocument CreatePdf (Stream stream) { - return CreatePdf (stream); + if (stream == null) { + throw new ArgumentNullException (nameof (stream)); + } + + var managed = new SKManagedWStream (stream); + return Owned (CreatePdf (managed), managed); } public static SKDocument CreatePdf (SKWStream stream) { if (stream == null) { - throw new ArgumentNullException (nameof(stream)); + throw new ArgumentNullException (nameof (stream)); } return GetObject (SkiaApi.sk_document_create_pdf_from_stream (stream.Handle)); } - [Obsolete("Use CreatePdf(SKWStream, SKDocumentPdfMetadata) instead.")] - public static SKDocument CreatePdf (SKWStream stream, SKDocumentPdfMetadata metadata, float dpi) + public static SKDocument CreatePdf (string path, float dpi) => + CreatePdf (path, new SKDocumentPdfMetadata (dpi)); + + public static SKDocument CreatePdf (Stream stream, float dpi) => + CreatePdf (stream, new SKDocumentPdfMetadata (dpi)); + + public static SKDocument CreatePdf (SKWStream stream, float dpi) => + CreatePdf (stream, new SKDocumentPdfMetadata (dpi)); + + public static SKDocument CreatePdf (string path, SKDocumentPdfMetadata metadata) { - return CreatePdf (stream, metadata); + if (path == null) { + throw new ArgumentNullException (nameof (path)); + } + + var stream = SKFileWStream.OpenStream (path); + return Owned (CreatePdf (stream, metadata), stream); + } + + public static SKDocument CreatePdf (Stream stream, SKDocumentPdfMetadata metadata) + { + if (stream == null) { + throw new ArgumentNullException (nameof (stream)); + } + + var managed = new SKManagedWStream (stream); + return Owned (CreatePdf (managed, metadata), managed); } public static SKDocument CreatePdf (SKWStream stream, SKDocumentPdfMetadata metadata) { if (stream == null) { - throw new ArgumentNullException (nameof(stream)); + throw new ArgumentNullException (nameof (stream)); } using (var title = SKString.Create (metadata.Title)) @@ -127,7 +163,10 @@ namespace SkiaSharp Subject = subject?.Handle ?? IntPtr.Zero, Keywords = keywords?.Handle ?? IntPtr.Zero, Creator = creator?.Handle ?? IntPtr.Zero, - Producer = producer?.Handle ?? IntPtr.Zero + Producer = producer?.Handle ?? IntPtr.Zero, + RasterDPI = metadata.RasterDpi, + PDFA = metadata.PdfA ? (byte)1 : (byte)0, + EncodingQuality = metadata.EncodingQuality, }; unsafe { @@ -144,6 +183,17 @@ namespace SkiaSharp } } } + + private static SKDocument Owned (SKDocument doc, SKWStream stream) + { + if (stream != null) { + if (doc != null) + doc.SetDisposeChild (stream); + else + stream.Dispose (); + } + + return doc; + } } } - diff --git a/externals/skia b/externals/skia index 0d23e1f2..512ec450 160000 --- a/externals/skia +++ b/externals/skia @@ -1 +1 @@ -Subproject commit 0d23e1f29cf40a90dc281013720b3d76219da9c6 +Subproject commit 512ec450f7fa2d7baaf0c8eba768126b09dcf2f7 diff --git a/tests/Tests/SKDocumentTest.cs b/tests/Tests/SKDocumentTest.cs index 8c8c89a9..32d55f6d 100644 --- a/tests/Tests/SKDocumentTest.cs +++ b/tests/Tests/SKDocumentTest.cs @@ -8,7 +8,6 @@ namespace SkiaSharp.Tests public class SKDocumentTest : SKTest { [SkippableFact] - [Obsolete] public void PdfFileIsClosed() { var path = Path.Combine(PathToImages, Guid.NewGuid().ToString("D") + ".pdf"); @@ -26,7 +25,6 @@ namespace SkiaSharp.Tests } [SkippableFact] - [Obsolete] public void PdfFileWithNonASCIIPathIsClosed() { var path = Path.Combine(PathToImages, Guid.NewGuid().ToString("D") + "上田雅美.pdf"); @@ -44,7 +42,6 @@ namespace SkiaSharp.Tests } [SkippableFact] - [Obsolete] public void XpsFileIsClosed() { var path = Path.Combine(PathToImages, Guid.NewGuid().ToString("D") + ".xps"); @@ -69,9 +66,8 @@ namespace SkiaSharp.Tests public void CanCreatePdf() { using (var stream = new MemoryStream()) - using (var managed = new SKManagedWStream(stream, false)) { - using (var doc = SKDocument.CreatePdf(managed)) + using (var doc = SKDocument.CreatePdf(stream)) { Assert.NotNull(doc); Assert.NotNull(doc.BeginPage(100, 100)); @@ -85,16 +81,64 @@ namespace SkiaSharp.Tests } } + [SkippableFact] + public void CanCreatePdfWithMetadata() + { + 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 ManagedStreamDisposeOrder() + { + using (var stream = new MemoryStream()) + using (var doc = SKDocument.CreatePdf(stream)) + { + Assert.NotNull(doc); + Assert.NotNull(doc.BeginPage(100, 100)); + + doc.EndPage(); + doc.Close(); + doc.Dispose(); + + stream.Flush(); + + Assert.True(stream.Length > 0); + Assert.True(stream.Position > 0); + } + } + [SkippableFact] public void CanCreateXps() { // XPS is only supported on Windows using (var stream = new MemoryStream()) - using (var managed = new SKManagedWStream(stream, false)) { using (new SKAutoCoInitialize()) - using (var doc = SKDocument.CreateXps(managed)) + using (var doc = SKDocument.CreateXps(stream)) { if (IsWindows) {