diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..4260584
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,8 @@
+# Changelog
+
+### [1.3.2-rc.3] - 2025-12-05
+- Converted from System.Drawing.Bitmap to SkiaSharp.SKBitmap for cross-platform support
+- Replaced System.Drawing.Common package with SkiaSharp (2.88.8)
+- Updated memory operations to work on both Windows and Linux
+- Fixed color accuracy by correctly handling BGR format from Ghostscript
+- Updated platform-specific structures for Linux compatibility
\ No newline at end of file
diff --git a/Ghostscript.NET.DisplayTest/FMain.cs b/Ghostscript.NET.DisplayTest/FMain.cs
index eef9b02..66f4c25 100644
--- a/Ghostscript.NET.DisplayTest/FMain.cs
+++ b/Ghostscript.NET.DisplayTest/FMain.cs
@@ -9,6 +9,8 @@
using Ghostscript.NET;
using Ghostscript.NET.Viewer;
using Ghostscript.NET.Interpreter;
+using SkiaSharp;
+using SkiaSharp.Views.Desktop;
namespace Ghostscript.NET.DisplayTest
{
@@ -17,6 +19,7 @@ public partial class FMain : Form
private GhostscriptViewer _viewer;
private FPreview _preview = new FPreview();
private StdIOHandler _stdioHandler;
+ private SKBitmap _currentBitmap = null;
public FMain()
{
@@ -48,19 +51,17 @@ private void FMain_Load(object sender, EventArgs e)
void _viewer_DisplayPage(object sender, GhostscriptViewerViewEventArgs e)
{
- _preview.pbDisplay.Invalidate();
- _preview.pbDisplay.Update();
+ _preview.UpdateImage(e.Image);
}
void _viewer_DisplayUpdate(object sender, GhostscriptViewerViewEventArgs e)
{
- _preview.pbDisplay.Invalidate();
- _preview.pbDisplay.Update();
+ _preview.UpdateImage(e.Image);
}
void _viewer_DisplaySize(object sender, GhostscriptViewerViewEventArgs e)
{
- _preview.pbDisplay.Image = e.Image;
+ _preview.UpdateImage(e.Image);
}
private void btnRun_Click(object sender, EventArgs e)
diff --git a/Ghostscript.NET.DisplayTest/FPreview.Designer.cs b/Ghostscript.NET.DisplayTest/FPreview.Designer.cs
index d9c248a..0d39bac 100644
--- a/Ghostscript.NET.DisplayTest/FPreview.Designer.cs
+++ b/Ghostscript.NET.DisplayTest/FPreview.Designer.cs
@@ -28,8 +28,7 @@ protected override void Dispose(bool disposing)
///
private void InitializeComponent()
{
- this.pbDisplay = new System.Windows.Forms.PictureBox();
- ((System.ComponentModel.ISupportInitialize)(this.pbDisplay)).BeginInit();
+ this.pbDisplay = new SkiaSharp.Views.Desktop.SKControl();
this.SuspendLayout();
//
// pbDisplay
@@ -37,9 +36,7 @@ private void InitializeComponent()
this.pbDisplay.Location = new System.Drawing.Point(0, 0);
this.pbDisplay.Name = "pbDisplay";
this.pbDisplay.Size = new System.Drawing.Size(75, 75);
- this.pbDisplay.SizeMode = System.Windows.Forms.PictureBoxSizeMode.AutoSize;
this.pbDisplay.TabIndex = 0;
- this.pbDisplay.TabStop = false;
//
// FPreview
//
@@ -52,14 +49,12 @@ private void InitializeComponent()
this.StartPosition = System.Windows.Forms.FormStartPosition.Manual;
this.Text = "Ghostscript.NET Display";
this.Load += new System.EventHandler(this.FPreview_Load);
- ((System.ComponentModel.ISupportInitialize)(this.pbDisplay)).EndInit();
this.ResumeLayout(false);
- this.PerformLayout();
}
#endregion
- public System.Windows.Forms.PictureBox pbDisplay;
+ public SkiaSharp.Views.Desktop.SKControl pbDisplay;
}
}
\ No newline at end of file
diff --git a/Ghostscript.NET.DisplayTest/FPreview.cs b/Ghostscript.NET.DisplayTest/FPreview.cs
index c0ce04e..1e3032f 100644
--- a/Ghostscript.NET.DisplayTest/FPreview.cs
+++ b/Ghostscript.NET.DisplayTest/FPreview.cs
@@ -6,22 +6,77 @@
using System.Linq;
using System.Text;
using System.Windows.Forms;
+using SkiaSharp;
+using SkiaSharp.Views.Desktop;
namespace Ghostscript.NET.DisplayTest
{
public partial class FPreview : Form
{
+ private SKBitmap _currentBitmap = null;
+
public FPreview()
{
InitializeComponent();
this.Left = 0;
this.Top = 0;
+
+ pbDisplay.PaintSurface += PbDisplay_PaintSurface;
+ }
+
+ private void PbDisplay_PaintSurface(object sender, SKPaintSurfaceEventArgs e)
+ {
+ var canvas = e.Surface.Canvas;
+ canvas.Clear(SKColors.White);
+
+ if (_currentBitmap != null)
+ {
+ var destRect = SKRect.Create(pbDisplay.Width, pbDisplay.Height);
+ var sourceRect = SKRect.Create(_currentBitmap.Width, _currentBitmap.Height);
+ canvas.DrawBitmap(_currentBitmap, sourceRect, destRect);
+ }
+ }
+
+ public void UpdateImage(SKBitmap bitmap)
+ {
+ _currentBitmap = bitmap;
+ ResizeCanvas(bitmap);
+ RefreshCanvas();
}
private void FPreview_Load(object sender, EventArgs e)
{
}
+
+ private void ResizeCanvas(SKBitmap bitmap)
+ {
+ if (bitmap == null)
+ {
+ return;
+ }
+
+ if (pbDisplay.Width == bitmap.Width && pbDisplay.Height == bitmap.Height)
+ {
+ return;
+ }
+
+ pbDisplay.SuspendLayout();
+ pbDisplay.Width = bitmap.Width;
+ pbDisplay.Height = bitmap.Height;
+ pbDisplay.ResumeLayout();
+ }
+
+ private void RefreshCanvas()
+ {
+ if (!pbDisplay.IsHandleCreated)
+ {
+ return;
+ }
+
+ pbDisplay.Invalidate();
+ pbDisplay.Update();
+ }
}
}
diff --git a/Ghostscript.NET.DisplayTest/Ghostscript.NET.DisplayTest.csproj b/Ghostscript.NET.DisplayTest/Ghostscript.NET.DisplayTest.csproj
index c005817..58b4002 100644
--- a/Ghostscript.NET.DisplayTest/Ghostscript.NET.DisplayTest.csproj
+++ b/Ghostscript.NET.DisplayTest/Ghostscript.NET.DisplayTest.csproj
@@ -1,8 +1,9 @@
net6.0-windows
- x86
- WinExe
+ AnyCPU
+ Exe
+ AnyCPU;x64
@@ -34,4 +35,8 @@
+
+
+
+
\ No newline at end of file
diff --git a/Ghostscript.NET.Samples/Program.cs b/Ghostscript.NET.Samples/Program.cs
index 9586a1e..e8ac4b6 100644
--- a/Ghostscript.NET.Samples/Program.cs
+++ b/Ghostscript.NET.Samples/Program.cs
@@ -24,10 +24,13 @@
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-using System;
-using System.Collections.Generic;
using Ghostscript.NET;
+using Ghostscript.NET.Rasterizer;
using Ghostscript.NET.Samples;
+using SkiaSharp;
+using System;
+using System.Collections.Generic;
+using System.IO;
Console.WriteLine("Ghostscript.NET Samples");
@@ -58,4 +61,26 @@
Console.WriteLine($"Sample '{sample.GetType().Name}' run successful!");
}
-Console.ReadLine();
+GhostscriptVersionInfo lastVersion = GhostscriptVersionInfo.GetLastInstalledVersion();
+
+using (var rasterizer = new GhostscriptRasterizer())
+{
+ rasterizer.Open(@"e:\Tmp\test.pdf", lastVersion, false);
+
+ for (var pageNumber = 1; pageNumber <= rasterizer.PageCount; pageNumber++)
+ {
+ var pageFilePath = Path.Combine(@"e:\Tmp\", string.Format("SkisSharp-{0}.png", pageNumber));
+
+ var img = rasterizer.GetPage(300, pageNumber);
+ using (var image = SKImage.FromBitmap(img))
+ using (var data = image.Encode(SKEncodedImageFormat.Png, 100))
+ using (var stream = File.OpenWrite(pageFilePath))
+ {
+ data.SaveTo(stream);
+ }
+
+ Console.WriteLine(pageFilePath);
+ }
+}
+
+Console.ReadKey();
\ No newline at end of file
diff --git a/Ghostscript.NET.Samples/Samples/RasterizerCropSample.cs b/Ghostscript.NET.Samples/Samples/RasterizerCropSample.cs
index 87bf7fd..7a0d9a8 100644
--- a/Ghostscript.NET.Samples/Samples/RasterizerCropSample.cs
+++ b/Ghostscript.NET.Samples/Samples/RasterizerCropSample.cs
@@ -25,9 +25,8 @@
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
using System;
-using System.Drawing;
-using System.Drawing.Imaging;
using System.IO;
+using SkiaSharp;
// required Ghostscript.NET namespaces
using Ghostscript.NET;
@@ -63,8 +62,16 @@ public void Start()
{
string pageFilePath = Path.Combine(outputPath, "Page-" + pageNumber.ToString() + ".png");
- Image img = rasterizer.GetPage(desired_dpi, pageNumber);
- img.Save(pageFilePath, ImageFormat.Png);
+ SKBitmap img = rasterizer.GetPage(desired_dpi, pageNumber);
+ if (img != null)
+ {
+ using (var image = SKImage.FromBitmap(img))
+ using (var data = image.Encode(SKEncodedImageFormat.Png, 100))
+ using (var stream = File.OpenWrite(pageFilePath))
+ {
+ data.SaveTo(stream);
+ }
+ }
Console.WriteLine(pageFilePath);
}
diff --git a/Ghostscript.NET.Samples/Samples/RasterizerSample1.cs b/Ghostscript.NET.Samples/Samples/RasterizerSample1.cs
index c211f77..2c060c9 100644
--- a/Ghostscript.NET.Samples/Samples/RasterizerSample1.cs
+++ b/Ghostscript.NET.Samples/Samples/RasterizerSample1.cs
@@ -30,6 +30,7 @@
using System.IO;
using Ghostscript.NET.Rasterizer;
using Ghostscript.NET.Samples.StdIOHandlers;
+using SkiaSharp;
namespace Ghostscript.NET.Samples
{
@@ -64,7 +65,15 @@ public void Sample1()
var pageFilePath = Path.Combine(outputPath, string.Format("Page-{0}.png", pageNumber));
var img = rasterizer.GetPage(desired_dpi, pageNumber);
- img.Save(pageFilePath, ImageFormat.Png);
+ if (img != null)
+ {
+ using (var image = SKImage.FromBitmap(img))
+ using (var data = image.Encode(SKEncodedImageFormat.Png, 100))
+ using (var stream = File.OpenWrite(pageFilePath))
+ {
+ data.SaveTo(stream);
+ }
+ }
Console.WriteLine(pageFilePath);
}
@@ -92,7 +101,15 @@ public void Sample2()
var pageFilePath = Path.Combine(outputPath, string.Format("Page-{0}.png", pageNumber));
var img = rasterizer.GetPage(desired_dpi, pageNumber);
- img.Save(pageFilePath, ImageFormat.Png);
+ if (img != null)
+ {
+ using (var image = SKImage.FromBitmap(img))
+ using (var data = image.Encode(SKEncodedImageFormat.Png, 100))
+ using (var stream = File.OpenWrite(pageFilePath))
+ {
+ data.SaveTo(stream);
+ }
+ }
Console.WriteLine(pageFilePath);
}
diff --git a/Ghostscript.NET.Samples/Samples/RasterizerSample2.cs b/Ghostscript.NET.Samples/Samples/RasterizerSample2.cs
index 90f9735..20f0d66 100644
--- a/Ghostscript.NET.Samples/Samples/RasterizerSample2.cs
+++ b/Ghostscript.NET.Samples/Samples/RasterizerSample2.cs
@@ -32,6 +32,7 @@
// required Ghostscript.NET namespaces
using Ghostscript.NET;
using Ghostscript.NET.Rasterizer;
+using SkiaSharp;
namespace Ghostscript.NET.Samples
{
@@ -67,8 +68,16 @@ public void Start()
{
string pageFilePath = Path.Combine(outputPath, "Page-" + pageNumber.ToString() + ".png");
- Image img = rasterizer.GetPage(desired_dpi, pageNumber);
- img.Save(pageFilePath, ImageFormat.Png);
+ var img = rasterizer.GetPage(desired_dpi, pageNumber);
+ if (img != null)
+ {
+ using (var image = SKImage.FromBitmap(img))
+ using (var data = image.Encode(SKEncodedImageFormat.Png, 100))
+ using (var stream = File.OpenWrite(pageFilePath))
+ {
+ data.SaveTo(stream);
+ }
+ }
Console.WriteLine(pageFilePath);
}
diff --git a/Ghostscript.NET.Samples/Samples/ViewerSample.cs b/Ghostscript.NET.Samples/Samples/ViewerSample.cs
index 7a0920e..5e440d4 100644
--- a/Ghostscript.NET.Samples/Samples/ViewerSample.cs
+++ b/Ghostscript.NET.Samples/Samples/ViewerSample.cs
@@ -26,7 +26,7 @@
using System;
using System.Collections.Generic;
-using System.Drawing;
+using SkiaSharp;
// required Ghostscript.NET namespaces
using Ghostscript.NET;
@@ -38,7 +38,7 @@ public class ViewerSample : ISample
{
private GhostscriptVersionInfo _lastInstalledVersion = null;
private GhostscriptViewer _viewer = null;
- private Bitmap _pdfPage = null;
+ private SKBitmap _pdfPage = null;
public void Start()
{
@@ -92,7 +92,7 @@ void _viewer_DisplayUpdate(object sender, GhostscriptViewerViewEventArgs e)
// it by calling PictureBox.Invalidate() and PictureBox.Update()
// methods. We dont need to set image reference again because
// Ghostscript.NET is changing Image object directly in the
- // memory and does not create new Bitmap instance.
+ // memory and does not create new SKBitmap instance.
}
// this is the last raised event after complete page is rasterized
diff --git a/Ghostscript.NET.VS2022.sln b/Ghostscript.NET.VS2022.sln
index 063c814..9d05cd1 100644
--- a/Ghostscript.NET.VS2022.sln
+++ b/Ghostscript.NET.VS2022.sln
@@ -46,18 +46,18 @@ Global
{294FE872-0D67-45B7-ADFB-1BA2F9EA01CD}.Release|x64.Build.0 = Release|x64
{294FE872-0D67-45B7-ADFB-1BA2F9EA01CD}.Release|x86.ActiveCfg = Release|Any CPU
{294FE872-0D67-45B7-ADFB-1BA2F9EA01CD}.Release|x86.Build.0 = Release|Any CPU
- {C099EB3A-B4D7-4379-AFAB-4FCD4DF4F003}.Debug|Any CPU.ActiveCfg = Debug|x86
- {C099EB3A-B4D7-4379-AFAB-4FCD4DF4F003}.Debug|Any CPU.Build.0 = Debug|x86
- {C099EB3A-B4D7-4379-AFAB-4FCD4DF4F003}.Debug|x64.ActiveCfg = Debug|Any CPU
- {C099EB3A-B4D7-4379-AFAB-4FCD4DF4F003}.Debug|x64.Build.0 = Debug|Any CPU
- {C099EB3A-B4D7-4379-AFAB-4FCD4DF4F003}.Debug|x86.ActiveCfg = Debug|x86
- {C099EB3A-B4D7-4379-AFAB-4FCD4DF4F003}.Debug|x86.Build.0 = Debug|x86
- {C099EB3A-B4D7-4379-AFAB-4FCD4DF4F003}.Release|Any CPU.ActiveCfg = Release|x86
- {C099EB3A-B4D7-4379-AFAB-4FCD4DF4F003}.Release|Any CPU.Build.0 = Release|x86
- {C099EB3A-B4D7-4379-AFAB-4FCD4DF4F003}.Release|x64.ActiveCfg = Release|Any CPU
- {C099EB3A-B4D7-4379-AFAB-4FCD4DF4F003}.Release|x64.Build.0 = Release|Any CPU
- {C099EB3A-B4D7-4379-AFAB-4FCD4DF4F003}.Release|x86.ActiveCfg = Release|x86
- {C099EB3A-B4D7-4379-AFAB-4FCD4DF4F003}.Release|x86.Build.0 = Release|x86
+ {C099EB3A-B4D7-4379-AFAB-4FCD4DF4F003}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {C099EB3A-B4D7-4379-AFAB-4FCD4DF4F003}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C099EB3A-B4D7-4379-AFAB-4FCD4DF4F003}.Debug|x64.ActiveCfg = Debug|x64
+ {C099EB3A-B4D7-4379-AFAB-4FCD4DF4F003}.Debug|x64.Build.0 = Debug|x64
+ {C099EB3A-B4D7-4379-AFAB-4FCD4DF4F003}.Debug|x86.ActiveCfg = Debug|x64
+ {C099EB3A-B4D7-4379-AFAB-4FCD4DF4F003}.Debug|x86.Build.0 = Debug|x64
+ {C099EB3A-B4D7-4379-AFAB-4FCD4DF4F003}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {C099EB3A-B4D7-4379-AFAB-4FCD4DF4F003}.Release|Any CPU.Build.0 = Release|Any CPU
+ {C099EB3A-B4D7-4379-AFAB-4FCD4DF4F003}.Release|x64.ActiveCfg = Release|x64
+ {C099EB3A-B4D7-4379-AFAB-4FCD4DF4F003}.Release|x64.Build.0 = Release|x64
+ {C099EB3A-B4D7-4379-AFAB-4FCD4DF4F003}.Release|x86.ActiveCfg = Release|x64
+ {C099EB3A-B4D7-4379-AFAB-4FCD4DF4F003}.Release|x86.Build.0 = Release|x64
{48CD0D6E-58A0-472C-8696-42084DECEF69}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{48CD0D6E-58A0-472C-8696-42084DECEF69}.Debug|Any CPU.Build.0 = Debug|Any CPU
{48CD0D6E-58A0-472C-8696-42084DECEF69}.Debug|x64.ActiveCfg = Debug|Any CPU
@@ -70,16 +70,16 @@ Global
{48CD0D6E-58A0-472C-8696-42084DECEF69}.Release|x64.Build.0 = Release|Any CPU
{48CD0D6E-58A0-472C-8696-42084DECEF69}.Release|x86.ActiveCfg = Release|Any CPU
{48CD0D6E-58A0-472C-8696-42084DECEF69}.Release|x86.Build.0 = Release|Any CPU
- {3509F0F7-A7AD-4FEE-B388-AA817F3413E9}.Debug|Any CPU.ActiveCfg = Debug|x64
- {3509F0F7-A7AD-4FEE-B388-AA817F3413E9}.Debug|Any CPU.Build.0 = Debug|x64
+ {3509F0F7-A7AD-4FEE-B388-AA817F3413E9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {3509F0F7-A7AD-4FEE-B388-AA817F3413E9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3509F0F7-A7AD-4FEE-B388-AA817F3413E9}.Debug|x64.ActiveCfg = Debug|x64
{3509F0F7-A7AD-4FEE-B388-AA817F3413E9}.Debug|x64.Build.0 = Debug|x64
{3509F0F7-A7AD-4FEE-B388-AA817F3413E9}.Debug|x86.ActiveCfg = Debug|x86
{3509F0F7-A7AD-4FEE-B388-AA817F3413E9}.Debug|x86.Build.0 = Debug|x86
- {3509F0F7-A7AD-4FEE-B388-AA817F3413E9}.Release|Any CPU.ActiveCfg = Release|x64
- {3509F0F7-A7AD-4FEE-B388-AA817F3413E9}.Release|Any CPU.Build.0 = Release|x64
- {3509F0F7-A7AD-4FEE-B388-AA817F3413E9}.Release|x64.ActiveCfg = Release|Any CPU
- {3509F0F7-A7AD-4FEE-B388-AA817F3413E9}.Release|x64.Build.0 = Release|Any CPU
+ {3509F0F7-A7AD-4FEE-B388-AA817F3413E9}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {3509F0F7-A7AD-4FEE-B388-AA817F3413E9}.Release|Any CPU.Build.0 = Release|Any CPU
+ {3509F0F7-A7AD-4FEE-B388-AA817F3413E9}.Release|x64.ActiveCfg = Release|x64
+ {3509F0F7-A7AD-4FEE-B388-AA817F3413E9}.Release|x64.Build.0 = Release|x64
{3509F0F7-A7AD-4FEE-B388-AA817F3413E9}.Release|x86.ActiveCfg = Release|x86
{3509F0F7-A7AD-4FEE-B388-AA817F3413E9}.Release|x86.Build.0 = Release|x86
EndGlobalSection
diff --git a/Ghostscript.NET.Viewer/FDebug.cs b/Ghostscript.NET.Viewer/FDebug.cs
index 41eb357..865d455 100644
--- a/Ghostscript.NET.Viewer/FDebug.cs
+++ b/Ghostscript.NET.Viewer/FDebug.cs
@@ -3,6 +3,7 @@
using System.ComponentModel;
using System.Data;
using System.Drawing;
+using SkiaSharp;
using System.Linq;
using System.Text;
using System.Windows.Forms;
diff --git a/Ghostscript.NET.Viewer/FMain.Designer.cs b/Ghostscript.NET.Viewer/FMain.Designer.cs
index e768994..0a7120a 100644
--- a/Ghostscript.NET.Viewer/FMain.Designer.cs
+++ b/Ghostscript.NET.Viewer/FMain.Designer.cs
@@ -69,7 +69,7 @@ private void InitializeComponent()
this.panel1 = new System.Windows.Forms.Panel();
this.panel2 = new System.Windows.Forms.Panel();
this.panel3 = new System.Windows.Forms.Panel();
- this.pbPage = new System.Windows.Forms.PictureBox();
+ this.pbPage = new SkiaSharp.Views.Desktop.SKControl();
this.mnuMain.SuspendLayout();
this.statusStrip1.SuspendLayout();
this.panTop.SuspendLayout();
@@ -78,7 +78,6 @@ private void InitializeComponent()
this.panGDN.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit();
this.panel3.SuspendLayout();
- ((System.ComponentModel.ISupportInitialize)(this.pbPage)).BeginInit();
this.SuspendLayout();
//
// mnuMain
@@ -444,9 +443,7 @@ private void InitializeComponent()
this.pbPage.Location = new System.Drawing.Point(4, 4);
this.pbPage.Name = "pbPage";
this.pbPage.Size = new System.Drawing.Size(126, 118);
- this.pbPage.SizeMode = System.Windows.Forms.PictureBoxSizeMode.AutoSize;
this.pbPage.TabIndex = 1;
- this.pbPage.TabStop = false;
//
// FMain
//
@@ -477,8 +474,6 @@ private void InitializeComponent()
this.panGDN.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit();
this.panel3.ResumeLayout(false);
- this.panel3.PerformLayout();
- ((System.ComponentModel.ISupportInitialize)(this.pbPage)).EndInit();
this.ResumeLayout(false);
this.PerformLayout();
@@ -517,7 +512,7 @@ private void InitializeComponent()
private System.Windows.Forms.Panel panel3;
private System.Windows.Forms.ToolStripStatusLabel lblGsVersion;
private System.Windows.Forms.ToolStripLabel tbTotalPages;
- private System.Windows.Forms.PictureBox pbPage;
+ private SkiaSharp.Views.Desktop.SKControl pbPage;
private System.Windows.Forms.ToolStripStatusLabel lblSystemInformation;
private System.Windows.Forms.ToolStripButton tpZoomOut;
private System.Windows.Forms.ToolStripButton tpZoomIn;
diff --git a/Ghostscript.NET.Viewer/FMain.cs b/Ghostscript.NET.Viewer/FMain.cs
index 71a7b3c..570e139 100644
--- a/Ghostscript.NET.Viewer/FMain.cs
+++ b/Ghostscript.NET.Viewer/FMain.cs
@@ -35,6 +35,8 @@
using System.IO;
using System.Runtime.InteropServices;
using Ghostscript.NET.Viewer;
+using SkiaSharp;
+using SkiaSharp.Views.Desktop;
namespace Ghostscript.NET.Viewer
{
@@ -45,6 +47,7 @@ public partial class FMain : Form
private StringBuilder _stdOut = new StringBuilder();
private StringBuilder _stdErr = new StringBuilder();
private bool _supressPageNumberChangeEvent = false;
+ private SKBitmap _currentBitmap = null;
public FMain()
{
@@ -54,6 +57,7 @@ public FMain()
pbPage.Width = 100;
pbPage.Height = 100;
+ pbPage.PaintSurface += PbPage_PaintSurface;
_viewer = new GhostscriptViewer();
_viewer.AttachStdIO(new GhostscriptStdIOHandler(_stdOut, _stdErr));
@@ -63,21 +67,37 @@ public FMain()
_viewer.DisplayPage += new GhostscriptViewerViewEventHandler(_viewer_DisplayPage);
}
+ private void PbPage_PaintSurface(object sender, SKPaintSurfaceEventArgs e)
+ {
+ var canvas = e.Surface.Canvas;
+ canvas.Clear(SKColors.White);
+
+ if (_currentBitmap != null)
+ {
+ var destRect = SKRect.Create(pbPage.Width, pbPage.Height);
+ var sourceRect = SKRect.Create(_currentBitmap.Width, _currentBitmap.Height);
+ canvas.DrawBitmap(_currentBitmap, sourceRect, destRect);
+ }
+ }
+
void _viewer_DisplaySize(object sender, GhostscriptViewerViewEventArgs e)
{
- pbPage.Image = e.Image;
+ _currentBitmap = e.Image;
+ ResizeCanvas(e.Image);
+ RefreshCanvas();
}
void _viewer_DisplayUpdate(object sender, GhostscriptViewerViewEventArgs e)
{
- pbPage.Invalidate();
- pbPage.Update();
+ _currentBitmap = e.Image;
+ RefreshCanvas();
}
void _viewer_DisplayPage(object sender, GhostscriptViewerViewEventArgs e)
{
- pbPage.Invalidate();
- pbPage.Update();
+ _currentBitmap = e.Image;
+ ResizeCanvas(e.Image);
+ RefreshCanvas();
_supressPageNumberChangeEvent = true;
tbPageNumber.Text = _viewer.CurrentPageNumber.ToString();
@@ -86,6 +106,35 @@ void _viewer_DisplayPage(object sender, GhostscriptViewerViewEventArgs e)
tbTotalPages.Text = " / " + _viewer.LastPageNumber.ToString();
}
+ private void ResizeCanvas(SKBitmap bitmap)
+ {
+ if (bitmap == null)
+ {
+ return;
+ }
+
+ if (pbPage.Width == bitmap.Width && pbPage.Height == bitmap.Height)
+ {
+ return;
+ }
+
+ pbPage.SuspendLayout();
+ pbPage.Width = bitmap.Width;
+ pbPage.Height = bitmap.Height;
+ pbPage.ResumeLayout();
+ }
+
+ private void RefreshCanvas()
+ {
+ if (!pbPage.IsHandleCreated)
+ {
+ return;
+ }
+
+ pbPage.Invalidate();
+ pbPage.Update();
+ }
+
private void FMain_Load(object sender, EventArgs e)
{
lblSystemInformation.Text = "Operating system: " + (Environment.Is64BitOperatingSystem ? "64-bit" : "32-bit") + " " +
@@ -120,7 +169,8 @@ private void mnuFileClose_Click(object sender, EventArgs e)
_stdOut.Clear();
_stdErr.Clear();
- pbPage.Image = null;
+ _currentBitmap = null;
+ pbPage.Invalidate();
this.Text = Program.NAME;
tbPageNumber.Text = string.Empty;
tbTotalPages.Text = string.Empty;
diff --git a/Ghostscript.NET.Viewer/Ghostscript.NET.Viewer.csproj b/Ghostscript.NET.Viewer/Ghostscript.NET.Viewer.csproj
index fd43b33..14a952c 100644
--- a/Ghostscript.NET.Viewer/Ghostscript.NET.Viewer.csproj
+++ b/Ghostscript.NET.Viewer/Ghostscript.NET.Viewer.csproj
@@ -29,4 +29,8 @@
+
+
+
+
\ No newline at end of file
diff --git a/Ghostscript.NET/Ghostscript.NET.csproj b/Ghostscript.NET/Ghostscript.NET.csproj
index 9f628cf..bb3d2bc 100644
--- a/Ghostscript.NET/Ghostscript.NET.csproj
+++ b/Ghostscript.NET/Ghostscript.NET.csproj
@@ -6,7 +6,7 @@
bin\$(Configuration)\$(TargetFramework)\Ghostscript.NET.xml
True
Ghostscript.NET
- 1.3.1
+ 1.3.2-rc.3
Artifex Software Inc.
Artifex
A C# binding for Ghostscript library
@@ -55,7 +55,7 @@
-
+
diff --git a/Ghostscript.NET/GhostscriptLibrary.cs b/Ghostscript.NET/GhostscriptLibrary.cs
index 50e8892..ac7c63e 100644
--- a/Ghostscript.NET/GhostscriptLibrary.cs
+++ b/Ghostscript.NET/GhostscriptLibrary.cs
@@ -277,7 +277,7 @@ private void InitializeWindows()
gsapi_revision_s rev = new gsapi_revision_s();
if (this.gsapi_revision(ref rev, System.Runtime.InteropServices.Marshal.SizeOf(rev)) == 0)
{
- _revision = rev.revision;
+ _revision = (int)rev.revision;
}
this.gsapi_new_instance = _library.GetDelegateForFunction("gsapi_new_instance");
@@ -374,7 +374,7 @@ private void InitializeLinux()
gsapi_revision_s rev = new gsapi_revision_s();
if (this.gsapi_revision(ref rev, System.Runtime.InteropServices.Marshal.SizeOf(rev)) == 0)
{
- _revision = rev.revision;
+ _revision = (int)rev.revision;
}
this.gsapi_new_instance = _crossPlatformLibrary.GetDelegateForFunction("gsapi_new_instance");
diff --git a/Ghostscript.NET/GhostscriptVersionInfo.cs b/Ghostscript.NET/GhostscriptVersionInfo.cs
index 95789be..d43248d 100644
--- a/Ghostscript.NET/GhostscriptVersionInfo.cs
+++ b/Ghostscript.NET/GhostscriptVersionInfo.cs
@@ -307,109 +307,88 @@ public static List GetInstalledVersionsLinux(Ghostscript
return versions;
}
+ // Library names to search for (in order of preference - newer versions first)
+ string[] libraryNames = { "libgs.so.10", "libgs.so.9", "libgs.so" };
+
// Search for libgs.so in common locations
string[] searchPaths = CrossPlatformNativeLibraryHelper.GetCommonInstallationPaths();
foreach (string basePath in searchPaths)
{
- if (Directory.Exists(basePath))
+ if (!Directory.Exists(basePath))
+ {
+ continue;
+ }
+
+ // Check for libraries directly in basePath
+ foreach (string libName in libraryNames)
{
- // Look for libgs.so directly
- string libPath = Path.Combine(basePath, "libgs.so.10");
+ string libPath = Path.Combine(basePath, libName);
if (File.Exists(libPath))
{
- try
- {
- // Try to get version information from the library
- Version version = GetVersionFromLinuxLibrary(libPath);
- if (version != null)
- {
- versions.Add(new GhostscriptVersionInfo(version, libPath, basePath, licenseType));
- }
- else
- {
- // If we can't get version info, create a generic version
- versions.Add(new GhostscriptVersionInfo(new Version(0, 0), libPath, basePath, licenseType));
- }
- }
- catch
- {
- // If we can't get version info, create a generic version
- versions.Add(new GhostscriptVersionInfo(new Version(0, 0), libPath, basePath, licenseType));
- }
+ TryAddVersion(versions, libPath, basePath, licenseType);
+ break; // Found a library in this path, no need to check other names
}
- else
+ }
+
+ // Look in subdirectories
+ try
+ {
+ string[] subdirs = Directory.GetDirectories(basePath);
+ string[] subdirPaths = { "lib", "lib64", "bin" };
+
+ foreach (string subdir in subdirs)
{
- libPath = Path.Combine(basePath, "libgs.so");
- if (File.Exists(libPath))
+ foreach (string subdirPath in subdirPaths)
{
- try
- {
- // Try to get version information from the library
- Version version = GetVersionFromLinuxLibrary(libPath);
- if (version != null)
- {
- versions.Add(new GhostscriptVersionInfo(version, libPath, basePath, licenseType));
- }
- else
- {
- // If we can't get version info, create a generic version
- versions.Add(new GhostscriptVersionInfo(new Version(0, 0), libPath, basePath, licenseType));
- }
- }
- catch
+ string subdirFullPath = Path.Combine(subdir, subdirPath);
+ if (!Directory.Exists(subdirFullPath))
{
- // If we can't get version info, create a generic version
- versions.Add(new GhostscriptVersionInfo(new Version(0, 0), libPath, basePath, licenseType));
+ continue;
}
- }
- }
- // Look in subdirectories
- try
- {
- string[] subdirs = Directory.GetDirectories(basePath);
- foreach (string subdir in subdirs)
- {
- string[] possiblePaths = {
- Path.Combine(subdir, "lib", "libgs.so.10"),
- Path.Combine(subdir, "lib64", "libgs.so.10"),
- Path.Combine(subdir, "bin", "libgs.so.10"),
- Path.Combine(subdir, "lib", "libgs.so"),
- Path.Combine(subdir, "lib64", "libgs.so"),
- Path.Combine(subdir, "bin", "libgs.so")
- };
-
- foreach (string possiblePath in possiblePaths)
+ foreach (string libName in libraryNames)
{
+ string possiblePath = Path.Combine(subdirFullPath, libName);
if (File.Exists(possiblePath))
{
- try
- {
- Version version = GetVersionFromLinuxLibrary(possiblePath);
- if (version != null)
- {
- versions.Add(new GhostscriptVersionInfo(version, possiblePath, subdir, licenseType));
- }
- }
- catch
- {
- versions.Add(new GhostscriptVersionInfo(new Version(0, 0), possiblePath, subdir, licenseType));
- }
+ TryAddVersion(versions, possiblePath, subdir, licenseType);
+ break; // Found a library in this subdirectory, no need to check other names
}
}
}
}
- catch
- {
- // Ignore directory access errors
- }
+ }
+ catch
+ {
+ // Ignore directory access errors
}
}
return versions;
}
+ ///
+ /// Helper method to try adding a version from a library path.
+ ///
+ private static void TryAddVersion(List versions, string libPath, string basePath, GhostscriptLicense licenseType)
+ {
+ try
+ {
+ Version version = GetVersionFromLinuxLibrary(libPath);
+ versions.Add(new GhostscriptVersionInfo(
+ version ?? new Version(0, 0),
+ libPath,
+ basePath,
+ licenseType));
+ }
+ catch
+ {
+ // If we can't get version info, create a generic version
+ versions.Add(new GhostscriptVersionInfo(new Version(0, 0), libPath, basePath, licenseType));
+ }
+ }
+
#endregion
#region GetVersionFromLinuxLibrary
diff --git a/Ghostscript.NET/Helpers/ImageMemoryHelper.cs b/Ghostscript.NET/Helpers/ImageMemoryHelper.cs
index 24e3123..10e763a 100644
--- a/Ghostscript.NET/Helpers/ImageMemoryHelper.cs
+++ b/Ghostscript.NET/Helpers/ImageMemoryHelper.cs
@@ -36,17 +36,18 @@ internal class ImageMemoryHelper
public unsafe static void Set24bppRgbImageColor(IntPtr image, int width, int height, byte r, byte g, byte b)
{
byte* ptr = (byte*)image;
- int stride = (((width * 3) + 3) & ~3);
+ int stride = (((width * 4) + 3) & ~3); // BGRA8888 is 4 bytes per pixel
- int padding = stride - (width * 3);
+ int padding = stride - (width * 4);
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
- *ptr++ = r;
- *ptr++ = g;
- *ptr++ = b;
+ *ptr++ = b; // B
+ *ptr++ = g; // G
+ *ptr++ = r; // R
+ *ptr++ = 255; // A (fully opaque)
}
ptr+=padding;
@@ -55,6 +56,35 @@ public unsafe static void Set24bppRgbImageColor(IntPtr image, int width, int hei
#endregion
+ #region ConvertRgb24ToBgra32
+
+ public unsafe static void ConvertRgb24ToBgra32(IntPtr srcBgr24, IntPtr destBgra32, int width, int height, int srcStride, int destStride)
+ {
+ byte* srcPtr = (byte*)srcBgr24;
+ byte* destPtr = (byte*)destBgra32;
+
+ for (int y = 0; y < height; y++)
+ {
+ byte* srcRow = srcPtr + (y * srcStride);
+ byte* destRow = destPtr + (y * destStride);
+
+ for (int x = 0; x < width; x++)
+ {
+ // Ghostscript provides BGR format (little-endian: Blue/Black first)
+ byte b = *srcRow++;
+ byte g = *srcRow++;
+ byte r = *srcRow++;
+
+ *destRow++ = b; // B
+ *destRow++ = g; // G
+ *destRow++ = r; // R
+ *destRow++ = 255; // A (fully opaque)
+ }
+ }
+ }
+
+ #endregion
+
#region CopyImagePartFrom
public static void CopyImagePartFrom(IntPtr src, IntPtr dest, int x, int y, int width, int height, int stride, int bytesPerPixel)
@@ -66,13 +96,17 @@ public static void CopyImagePartFrom(IntPtr src, IntPtr dest, int x, int y, int
int srcBottom = y + height - 1;
int posSrcTop = 0;
int posDestTop = 0;
+ int bytesToCopy = width * bytesPerPixel;
while (srcTop <= srcBottom)
{
posSrcTop = (srcTop * (stride)) + (x * bytesPerPixel);
posDestTop = (destTop * (destStride));
- wdm.MoveMemory(new IntPtr((long)dest + posDestTop), new IntPtr((long)src + posSrcTop), (uint)(width * bytesPerPixel));
+ // Cross-platform memory copy using Marshal.Copy
+ byte[] buffer = new byte[bytesToCopy];
+ Marshal.Copy(new IntPtr((long)src + posSrcTop), buffer, 0, bytesToCopy);
+ Marshal.Copy(buffer, 0, new IntPtr((long)dest + posDestTop), bytesToCopy);
srcTop++;
destTop++;
@@ -92,13 +126,17 @@ public static void CopyImagePartTo(IntPtr dest, IntPtr src, int x, int y, int wi
int destBottom = y + height - 1;
int posDestTop = 0;
int posSrcTop = 0;
+ int bytesToCopy = width * bytesPerPixel;
while (destTop <= destBottom)
{
posDestTop = (destTop * stride) + (x * bytesPerPixel);
posSrcTop = (srcTop * partStride);
- wdm.MoveMemory(new IntPtr((long)dest + posDestTop), new IntPtr((long)src + posSrcTop), (uint)(width * bytesPerPixel));
+ // Cross-platform memory copy using Marshal.Copy
+ byte[] buffer = new byte[bytesToCopy];
+ Marshal.Copy(new IntPtr((long)src + posSrcTop), buffer, 0, bytesToCopy);
+ Marshal.Copy(buffer, 0, new IntPtr((long)dest + posDestTop), bytesToCopy);
destTop++;
srcTop++;
@@ -107,6 +145,43 @@ public static void CopyImagePartTo(IntPtr dest, IntPtr src, int x, int y, int wi
#endregion
+ #region CopyImagePartToRgb24ToBgra32
+
+ public unsafe static void CopyImagePartToRgb24ToBgra32(IntPtr destBgra32, IntPtr srcBgr24, int x, int y, int width, int height, int destStride, int srcStride)
+ {
+ byte* srcPtr = (byte*)srcBgr24;
+ byte* destPtr = (byte*)destBgra32;
+
+ for (int row = 0; row < height; row++)
+ {
+ int srcY = row;
+ int destY = y + row;
+
+ byte* srcRow = srcPtr + (srcY * srcStride);
+ byte* destRow = destPtr + (destY * destStride) + (x * 4); // BGRA is 4 bytes per pixel
+
+ for (int col = 0; col < width; col++)
+ {
+ int srcX = col;
+ byte* srcPixel = srcRow + (srcX * 3); // BGR is 3 bytes per pixel
+
+ // Ghostscript provides BGR format (little-endian: Blue/Black first)
+ byte b = srcPixel[0];
+ byte g = srcPixel[1];
+ byte r = srcPixel[2];
+
+ destRow[0] = b; // B
+ destRow[1] = g; // G
+ destRow[2] = r; // R
+ destRow[3] = 255; // A (fully opaque)
+
+ destRow += 4;
+ }
+ }
+ }
+
+ #endregion
+
#region FlipImageVertically
public static void FlipImageVertically(IntPtr src, IntPtr dest, int height, int stride)
diff --git a/Ghostscript.NET/OutputDevices/GhostscriptDevice.cs b/Ghostscript.NET/OutputDevices/GhostscriptDevice.cs
index 6ffa9c9..7a0ab9b 100644
--- a/Ghostscript.NET/OutputDevices/GhostscriptDevice.cs
+++ b/Ghostscript.NET/OutputDevices/GhostscriptDevice.cs
@@ -27,7 +27,7 @@
using System;
using System.Collections.Generic;
using System.Reflection;
-using System.Drawing;
+using SkiaSharp;
using Ghostscript.NET.Processor;
namespace Ghostscript.NET
@@ -189,11 +189,11 @@ public string[] GetSwitches()
parameters.Add(string.Format(switchName, valueAttribute.Value));
}
}
- else if (valueType == typeof(Color))
+ else if (valueType == typeof(SKColor))
{
- Color color = (Color)value;
+ SKColor color = (SKColor)value;
- string hexColor = "16#" + color.R.ToString("X2") + color.G.ToString("X2") + color.B.ToString("X2");
+ string hexColor = "16#" + color.Red.ToString("X2") + color.Green.ToString("X2") + color.Blue.ToString("X2");
parameters.Add(string.Format(switchName, hexColor));
}
diff --git a/Ghostscript.NET/OutputDevices/GhostscriptJpegDevice.cs b/Ghostscript.NET/OutputDevices/GhostscriptJpegDevice.cs
index 8b96ae3..772500b 100644
--- a/Ghostscript.NET/OutputDevices/GhostscriptJpegDevice.cs
+++ b/Ghostscript.NET/OutputDevices/GhostscriptJpegDevice.cs
@@ -25,7 +25,7 @@
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
using System;
-using System.Drawing;
+using SkiaSharp;
namespace Ghostscript.NET
{
diff --git a/Ghostscript.NET/OutputDevices/GhostscriptPngDevice.cs b/Ghostscript.NET/OutputDevices/GhostscriptPngDevice.cs
index 9537050..d154a94 100644
--- a/Ghostscript.NET/OutputDevices/GhostscriptPngDevice.cs
+++ b/Ghostscript.NET/OutputDevices/GhostscriptPngDevice.cs
@@ -25,7 +25,7 @@
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
using System;
-using System.Drawing;
+using SkiaSharp;
namespace Ghostscript.NET
{
@@ -142,7 +142,7 @@ public GhostscriptPngDevice(GhostscriptPngDeviceType deviceType)
#region BackgroundColor
[GhostscriptSwitch("-dBackgroundColor={0}")]
- public Color? BackgroundColor { get; set; }
+ public SKColor? BackgroundColor { get; set; }
#endregion
diff --git a/Ghostscript.NET/Rasterizer/GhostscriptRasterizer.cs b/Ghostscript.NET/Rasterizer/GhostscriptRasterizer.cs
index 7d915cc..a3faee4 100644
--- a/Ghostscript.NET/Rasterizer/GhostscriptRasterizer.cs
+++ b/Ghostscript.NET/Rasterizer/GhostscriptRasterizer.cs
@@ -26,9 +26,9 @@
using System;
using System.IO;
-using System.Drawing;
using Ghostscript.NET.Viewer;
using System.Collections.Generic;
+using SkiaSharp;
namespace Ghostscript.NET.Rasterizer
{
@@ -39,7 +39,7 @@ public class GhostscriptRasterizer : IDisposable
private bool _disposed = false;
private GhostscriptViewer _viewer;
- private Image _lastRasterizedImage = null;
+ private SKBitmap _lastRasterizedImage = null;
private GhostscriptViewerState _gsViewState;
#endregion
@@ -280,12 +280,12 @@ public int PageCount
#region GetPage
///
- /// Gets PDF page as System.Drawing.Image.
+ /// Gets PDF page as SkiaSharp.SKBitmap.
///
/// Desired dpi.
/// The page number.
- /// PDF page represented as System.Drawing.Image.
- public Image GetPage(int dpi, int pageNumber)
+ /// PDF page represented as SkiaSharp.SKBitmap.
+ public SKBitmap GetPage(int dpi, int pageNumber)
{
_viewer.Dpi = dpi;
_viewer.ShowPage(pageNumber, true);
@@ -300,7 +300,7 @@ void _viewer_DisplayPage(object sender, GhostscriptViewerViewEventArgs e)
{
if (e.Image != null)
{
- _lastRasterizedImage = e.Image.Clone() as Image;
+ _lastRasterizedImage = e.Image.Copy();
}
}
diff --git a/Ghostscript.NET/Viewer/FormatHandlers/GhostscriptViewerDefaultFormatHandler.cs b/Ghostscript.NET/Viewer/FormatHandlers/GhostscriptViewerDefaultFormatHandler.cs
index 658f08d..6b8434f 100644
--- a/Ghostscript.NET/Viewer/FormatHandlers/GhostscriptViewerDefaultFormatHandler.cs
+++ b/Ghostscript.NET/Viewer/FormatHandlers/GhostscriptViewerDefaultFormatHandler.cs
@@ -27,7 +27,6 @@
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
using System;
-using System.Drawing;
namespace Ghostscript.NET.Viewer
{
diff --git a/Ghostscript.NET/Viewer/FormatHandlers/GhostscriptViewerPdfFormatHandler.cs b/Ghostscript.NET/Viewer/FormatHandlers/GhostscriptViewerPdfFormatHandler.cs
index db13b45..40c2390 100644
--- a/Ghostscript.NET/Viewer/FormatHandlers/GhostscriptViewerPdfFormatHandler.cs
+++ b/Ghostscript.NET/Viewer/FormatHandlers/GhostscriptViewerPdfFormatHandler.cs
@@ -27,7 +27,6 @@
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
using System;
-using System.Drawing;
using System.Globalization;
namespace Ghostscript.NET.Viewer
diff --git a/Ghostscript.NET/Viewer/FormatHandlers/GhostscriptViewerPsFormatHandler.cs b/Ghostscript.NET/Viewer/FormatHandlers/GhostscriptViewerPsFormatHandler.cs
index b9819fe..d0f3c0d 100644
--- a/Ghostscript.NET/Viewer/FormatHandlers/GhostscriptViewerPsFormatHandler.cs
+++ b/Ghostscript.NET/Viewer/FormatHandlers/GhostscriptViewerPsFormatHandler.cs
@@ -27,7 +27,6 @@
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
using System;
-using System.Drawing;
using System.IO;
using System.Text;
using System.Collections.Generic;
diff --git a/Ghostscript.NET/Viewer/GhostscriptViewer.cs b/Ghostscript.NET/Viewer/GhostscriptViewer.cs
index 7f21b75..665cbe1 100644
--- a/Ghostscript.NET/Viewer/GhostscriptViewer.cs
+++ b/Ghostscript.NET/Viewer/GhostscriptViewer.cs
@@ -26,7 +26,6 @@
using System;
using System.IO;
-using System.Drawing;
using System.Collections.Generic;
using System.Globalization;
using Ghostscript.NET.Interpreter;
diff --git a/Ghostscript.NET/Viewer/GhostscriptViewerDisplayHandler.cs b/Ghostscript.NET/Viewer/GhostscriptViewerDisplayHandler.cs
index 292248f..a281447 100644
--- a/Ghostscript.NET/Viewer/GhostscriptViewerDisplayHandler.cs
+++ b/Ghostscript.NET/Viewer/GhostscriptViewerDisplayHandler.cs
@@ -26,9 +26,8 @@
using System;
using System.Text;
-using System.Drawing;
-using System.Drawing.Imaging;
using System.Runtime.InteropServices;
+using SkiaSharp;
namespace Ghostscript.NET.Viewer
{
@@ -99,7 +98,7 @@ public override int Presize(IntPtr handle, IntPtr device, int width, int height,
_destImage.Dispose(); _destImage = null;
}
- _destImage = GhostscriptViewerImage.Create(width, height, raster, PixelFormat.Format24bppRgb);
+ _destImage = GhostscriptViewerImage.Create(width, height, raster, SKColorType.Bgra8888);
return 0;
}
@@ -119,11 +118,11 @@ public override int Size(IntPtr handle, IntPtr device, int width, int height, in
_destImage.Dispose(); _destImage = null;
}
- _destImage = GhostscriptViewerImage.Create(width, height, raster, PixelFormat.Format24bppRgb);
+ _destImage = GhostscriptViewerImage.Create(width, height, raster, SKColorType.Bgra8888);
_viewer.FormatHandler.ShowPagePostScriptCommandInvoked = false;
- _viewer.RaiseDisplaySize(new GhostscriptViewerViewEventArgs(_destImage, new Rectangle(0, 0, width, height)));
+ _viewer.RaiseDisplaySize(new GhostscriptViewerViewEventArgs(_destImage, new SKRectI(0, 0, width, height)));
return 0;
}
@@ -149,21 +148,30 @@ public override int Page(IntPtr handle, IntPtr device, int copies, int flush)
if (!_viewer.ProgressiveUpdate || _viewer.Interpreter.GhostscriptLibrary.Revision > 950)
{
- int bytesPerPixel = 3;
+ int srcBytesPerPixel = 3; // BGR from Ghostscript (little-endian: Blue/Black first)
+ int destBytesPerPixel = 4; // BGRA for SkiaSharp
_destImage.Lock();
- IntPtr tempTile = Marshal.AllocHGlobal(_destImage.Stride * _destImage.Height);
+ // Allocate temporary buffer for BGR24 data
+ int srcStrideSize = (((_destImage.Width * srcBytesPerPixel) + 3) & ~3);
+ IntPtr tempTile = Marshal.AllocHGlobal(srcStrideSize * _destImage.Height);
- ImageMemoryHelper.CopyImagePartFrom(_srcImage, tempTile, 0, 0, _destImage.Width, _destImage.Height, _srcStride, bytesPerPixel);
- ImageMemoryHelper.FlipImageVertically(tempTile, _destImage.Scan0, _destImage.Height, _destImage.Stride);
+ // Copy BGR24 from source
+ ImageMemoryHelper.CopyImagePartFrom(_srcImage, tempTile, 0, 0, _destImage.Width, _destImage.Height, _srcStride, srcBytesPerPixel);
+
+ // Flip vertically
+ ImageMemoryHelper.FlipImageVertically(tempTile, tempTile, _destImage.Height, srcStrideSize);
+
+ // Convert BGR24 to BGRA32 and copy to destination
+ ImageMemoryHelper.ConvertRgb24ToBgra32(tempTile, _destImage.Scan0, _destImage.Width, _destImage.Height, srcStrideSize, _destImage.Stride);
Marshal.FreeHGlobal(tempTile);
_destImage.Unlock();
}
- _viewer.RaiseDisplayPage(new GhostscriptViewerViewEventArgs(_destImage, new Rectangle(0, 0, _destImage.Width, _destImage.Height)));
+ _viewer.RaiseDisplayPage(new GhostscriptViewerViewEventArgs(_destImage, new SKRectI(0, 0, _destImage.Width, _destImage.Height)));
return 0;
}
@@ -176,14 +184,14 @@ public override int Update(IntPtr handle, IntPtr device, int x, int y, int w, in
{
if (_viewer.ProgressiveUpdate)
{
- int bytesPerPixel = 3;
+ int srcBytesPerPixel = 3; // BGR from Ghostscript (little-endian: Blue/Black first)
+ int destBytesPerPixel = 4; // BGRA for SkiaSharp
if (_srcImage != IntPtr.Zero)
{
_destImage.Lock();
- int destStrideSize = (((_destImage.Width * bytesPerPixel) + 3) & ~3);
- int tileStride = (((w * bytesPerPixel) + 3) & ~3);
+ int srcTileStride = (((w * srcBytesPerPixel) + 3) & ~3);
if (_synchTriggered)
{
@@ -199,15 +207,19 @@ public override int Update(IntPtr handle, IntPtr device, int x, int y, int w, in
return 0;
}
- IntPtr tempTile = Marshal.AllocHGlobal(tileStride * h);
+ // Allocate temporary buffer for BGR24 tile
+ IntPtr tempTile = Marshal.AllocHGlobal(srcTileStride * h);
- ImageMemoryHelper.CopyImagePartFrom(_srcImage, tempTile, x, y, w, h, _srcStride, bytesPerPixel);
+ // Copy BGR24 tile from source
+ ImageMemoryHelper.CopyImagePartFrom(_srcImage, tempTile, x, y, w, h, _srcStride, srcBytesPerPixel);
- ImageMemoryHelper.FlipImageVertically(tempTile, tempTile, h, tileStride);
+ // Flip vertically
+ ImageMemoryHelper.FlipImageVertically(tempTile, tempTile, h, srcTileStride);
int tileMirrorY = _destImage.Height - y - h;
- ImageMemoryHelper.CopyImagePartTo(_destImage.Scan0, tempTile, x, tileMirrorY, w, h, destStrideSize, bytesPerPixel);
+ // Convert BGR24 to BGRA32 and copy to destination
+ ImageMemoryHelper.CopyImagePartToRgb24ToBgra32(_destImage.Scan0, tempTile, x, tileMirrorY, w, h, _destImage.Stride, srcTileStride);
Marshal.FreeHGlobal(tempTile);
@@ -217,7 +229,7 @@ public override int Update(IntPtr handle, IntPtr device, int x, int y, int w, in
{
_lastUpdateTime = Environment.TickCount;
- _viewer.RaiseDisplayUpdate(new GhostscriptViewerViewEventArgs(_destImage, new Rectangle(0, 0, _destImage.Width, _destImage.Height)));
+ _viewer.RaiseDisplayUpdate(new GhostscriptViewerViewEventArgs(_destImage, new SKRectI(0, 0, _destImage.Width, _destImage.Height)));
}
}
}
diff --git a/Ghostscript.NET/Viewer/GhostscriptViewerFormatHandler.cs b/Ghostscript.NET/Viewer/GhostscriptViewerFormatHandler.cs
index 0ed6234..42321b9 100644
--- a/Ghostscript.NET/Viewer/GhostscriptViewerFormatHandler.cs
+++ b/Ghostscript.NET/Viewer/GhostscriptViewerFormatHandler.cs
@@ -25,7 +25,6 @@
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
using System;
-using System.Drawing;
namespace Ghostscript.NET.Viewer
{
diff --git a/Ghostscript.NET/Viewer/GhostscriptViewerImage.cs b/Ghostscript.NET/Viewer/GhostscriptViewerImage.cs
index 78064f6..9334ab2 100644
--- a/Ghostscript.NET/Viewer/GhostscriptViewerImage.cs
+++ b/Ghostscript.NET/Viewer/GhostscriptViewerImage.cs
@@ -25,8 +25,7 @@
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
using System;
-using System.Drawing;
-using System.Drawing.Imaging;
+using SkiaSharp;
namespace Ghostscript.NET.Viewer
{
@@ -38,24 +37,22 @@ public class GhostscriptViewerImage : IDisposable
private bool _disposed = false;
private int _width;
private int _height;
- private Rectangle _rect;
private int _stride;
- private Bitmap _bitmap;
- private BitmapData _bitmapData;
+ private SKBitmap _bitmap;
+ private IntPtr _pixelsPtr;
+ private bool _isLocked = false;
#endregion
#region Constructor
- public GhostscriptViewerImage(int width, int height, int stride, PixelFormat format)
+ public GhostscriptViewerImage(int width, int height, int stride, SKColorType colorType)
{
_width = width;
_height = height;
_stride = stride;
- _rect = new Rectangle(0, 0, _width, _height);
-
- _bitmap = new Bitmap(width, height, format);
+ _bitmap = new SKBitmap(width, height, colorType, SKAlphaType.Opaque);
}
#endregion
@@ -89,12 +86,12 @@ protected virtual void Dispose(bool disposing)
{
if (disposing)
{
- if (_bitmapData != null)
+ if (_isLocked)
{
this.Unlock();
}
- _bitmap.Dispose();
+ _bitmap?.Dispose();
_bitmap = null;
}
@@ -108,9 +105,9 @@ protected virtual void Dispose(bool disposing)
#region Create
- public static GhostscriptViewerImage Create(int width, int height, int stride, PixelFormat format)
+ public static GhostscriptViewerImage Create(int width, int height, int stride, SKColorType colorType)
{
- GhostscriptViewerImage gvi = new GhostscriptViewerImage(width, height, stride, format);
+ GhostscriptViewerImage gvi = new GhostscriptViewerImage(width, height, stride, colorType);
return gvi;
}
@@ -120,9 +117,10 @@ public static GhostscriptViewerImage Create(int width, int height, int stride, P
internal void Lock()
{
- if (_bitmapData == null)
+ if (!_isLocked)
{
- _bitmapData = _bitmap.LockBits(_rect, ImageLockMode.WriteOnly, _bitmap.PixelFormat);
+ _pixelsPtr = _bitmap.GetPixels();
+ _isLocked = true;
}
}
@@ -132,7 +130,7 @@ internal void Lock()
internal IntPtr Scan0
{
- get { return _bitmapData.Scan0; }
+ get { return _pixelsPtr; }
}
#endregion
@@ -141,7 +139,7 @@ internal IntPtr Scan0
public int Stride
{
- get { return _bitmapData.Stride; }
+ get { return _bitmap.RowBytes; }
}
#endregion
@@ -150,10 +148,10 @@ public int Stride
internal void Unlock()
{
- if (_bitmapData != null)
+ if (_isLocked)
{
- _bitmap.UnlockBits(_bitmapData);
- _bitmapData = null;
+ _pixelsPtr = IntPtr.Zero;
+ _isLocked = false;
}
}
@@ -179,7 +177,7 @@ public int Height
#region Bitmap
- public Bitmap @Bitmap
+ public SKBitmap @Bitmap
{
get { return _bitmap; }
}
diff --git a/Ghostscript.NET/Viewer/GhostscriptViewerView.cs b/Ghostscript.NET/Viewer/GhostscriptViewerView.cs
index 0ae01b0..8f2317e 100644
--- a/Ghostscript.NET/Viewer/GhostscriptViewerView.cs
+++ b/Ghostscript.NET/Viewer/GhostscriptViewerView.cs
@@ -25,7 +25,7 @@
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
using System;
-using System.Drawing;
+using SkiaSharp;
namespace Ghostscript.NET.Viewer
{
@@ -40,23 +40,23 @@ public class GhostscriptViewerViewEventArgs : EventArgs
#region Private variables
private GhostscriptViewerImage _image;
- private RectangleF _mediaBox;
+ private SKRect _mediaBox;
#endregion
#region Constructor
- internal GhostscriptViewerViewEventArgs(GhostscriptViewerImage image, Rectangle mediaBox)
+ internal GhostscriptViewerViewEventArgs(GhostscriptViewerImage image, SKRectI mediaBox)
{
_image = image;
- _mediaBox = mediaBox;
+ _mediaBox = new SKRect(mediaBox.Left, mediaBox.Top, mediaBox.Right, mediaBox.Bottom);
}
#endregion
#region Image
- public Bitmap Image
+ public SKBitmap Image
{
get { return _image.Bitmap; }
}
@@ -66,7 +66,7 @@ public Bitmap Image
#region MediaBox
- public RectangleF MediaBox
+ public SKRect MediaBox
{
get { return _mediaBox; }
}
diff --git a/Ghostscript.NET/gs/iapi.h.cs b/Ghostscript.NET/gs/iapi.h.cs
index 9717661..eb17c14 100644
--- a/Ghostscript.NET/gs/iapi.h.cs
+++ b/Ghostscript.NET/gs/iapi.h.cs
@@ -39,8 +39,8 @@ public struct gsapi_revision_s
{
public IntPtr product;
public IntPtr copyright;
- public int revision;
- public int revisiondate;
+ public long revision;
+ public long revisiondate;
}
#endregion