Skip to content

Commit 3c8c4ff

Browse files
author
LoneWandererProductions
committed
sync back some improvements.
1 parent 8bef1ff commit 3c8c4ff

4 files changed

Lines changed: 128 additions & 52 deletions

File tree

Imaging/ImageExtension.cs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,16 +22,17 @@ namespace Imaging;
2222
public static class ImageExtension
2323
{
2424
/// <summary>
25-
/// Extension Method
26-
/// Converts Bitmap to BitmapImage.
25+
/// Extension Method
26+
/// Converts Bitmap to BitmapImage.
2727
/// </summary>
2828
/// <param name="bmp">The Bitmap.</param>
29+
/// <param name="lossless">if set to <c>true</c> [lossless].</param>
2930
/// <returns>
30-
/// A BitmapImage
31+
/// A BitmapImage
3132
/// </returns>
32-
public static BitmapImage ToBitmapImage(this Bitmap bmp)
33+
public static BitmapImage ToBitmapImage(this Bitmap bmp, bool lossless = false)
3334
{
34-
return ImageStreamMedia.BitmapToBitmapImage(bmp);
35+
return ImageStreamMedia.BitmapToBitmapImage(bmp, lossless);
3536
}
3637

3738
/// <summary>
@@ -89,4 +90,4 @@ public static float[] ConvertColorToOpenGlFormat(this Color color)
8990
color.A / 255.0f // Alpha
9091
};
9192
}
92-
}
93+
}

Imaging/ImageRender.cs

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -358,16 +358,17 @@ public BitmapImage GetBitmapImageFileStream(string path, int width, int height)
358358

359359
/// <inheritdoc />
360360
/// <summary>
361-
/// Converts to bitmap image.
361+
/// Bitmaps to bitmap image.
362362
/// </summary>
363-
/// <param name="image">The bitmap.</param>
364-
/// The Image as
365-
/// <see cref="BitmapImage" />
366-
/// .
363+
/// <param name="image">The image.</param>
364+
/// <param name="lossless">if set to <c>true</c> [lossless].</param>
365+
/// <returns>
366+
/// The Image as <see cref="BitmapImage" />.
367+
/// </returns>
367368
/// <exception cref="ArgumentNullException"></exception>
368-
public BitmapImage BitmapToBitmapImage(Bitmap image)
369+
public BitmapImage BitmapToBitmapImage(Bitmap image, bool lossless = false)
369370
{
370-
return ImageStreamMedia.BitmapToBitmapImage(image);
371+
return ImageStreamMedia.BitmapToBitmapImage(image, lossless);
371372
}
372373

373374
/// <inheritdoc />
@@ -850,4 +851,4 @@ public string BitmapImageToBase64(BitmapImage bitmapImage)
850851
{
851852
return Helpers.ImageConverter.BitmapImageToBase64(bitmapImage);
852853
}
853-
}
854+
}

Imaging/ImageStreamMedia.cs

Lines changed: 101 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,20 @@
77
* SOURCE: https://lodev.org/cgtutor/floodfill.html
88
*/
99

10+
using Imaging.Helpers;
1011
using System;
1112
using System.Diagnostics;
1213
using System.Drawing;
1314
using System.Drawing.Imaging;
1415
using System.IO;
16+
using System.Windows;
17+
using System.Windows.Media;
1518
using System.Windows.Media.Imaging;
16-
using Imaging.Helpers;
1719

1820
namespace Imaging;
1921

2022
/// <summary>
21-
/// Handle the more newer wpf Libraries
23+
/// Handle the more newer wpf Libraries
2224
/// </summary>
2325
public static class ImageStreamMedia
2426
{
@@ -140,52 +142,122 @@ internal static Bitmap BitmapImageToBitmap(BitmapImage image)
140142
}
141143

142144
/// <summary>
143-
/// Converts to bitmap image.
144-
/// https://stackoverflow.com/questions/5199205/how-do-i-rotate-image-then-move-to-the-top-left-0-0-without-cutting-off-the-imag/5200280#5200280
145+
/// Converts to bitmap image.
146+
/// https://stackoverflow.com/questions/5199205/how-do-i-rotate-image-then-move-to-the-top-left-0-0-without-cutting-off-the-imag/5200280#5200280
145147
/// </summary>
146148
/// <param name="image">The bitmap.</param>
149+
/// <param name="lossless">if set to <c>true</c> [lossless].</param>
150+
/// <returns>BitmpaImage from Bitmap</returns>
151+
/// <exception cref="ArgumentNullException">if Image is null</exception>
147152
/// The Image as
148153
/// <see cref="BitmapImage" />
149154
/// .
150-
/// <exception cref="ArgumentNullException">if Image is null</exception>
151-
internal static BitmapImage BitmapToBitmapImage(Bitmap image)
155+
internal static BitmapImage BitmapToBitmapImage(Bitmap image, bool lossless = false)
152156
{
157+
if (!lossless)
158+
return FastConvert(image);
159+
153160
ImageHelper.ValidateImage(nameof(BitmapToBitmapImage), image);
154161

155-
Bitmap tempImage = null;
162+
Bitmap processed = image;
163+
Bitmap? tempImage = null;
156164

157-
// Convert the image to Format32bppArgb if necessary
158-
if (image.PixelFormat != PixelFormat.Format32bppArgb)
165+
// Normalize to 32bppArgb if needed
166+
if (image.PixelFormat != System.Drawing.Imaging.PixelFormat.Format32bppArgb)
159167
{
160-
tempImage = new Bitmap(image.Width, image.Height, PixelFormat.Format32bppArgb);
168+
tempImage = new Bitmap(image.Width, image.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
169+
161170
using (var g = Graphics.FromImage(tempImage))
162-
{
163171
g.DrawImage(image, 0, 0);
164-
}
165172

166-
image = tempImage;
173+
processed = tempImage;
167174
}
168175

169176
try
170177
{
171-
// Create a memory stream and save the image in a compatible format (e.g., PNG)
172-
using var memoryStream = new MemoryStream();
173-
image.Save(memoryStream, ImageFormat.Png);
174-
memoryStream.Position = 0;
175-
176-
// Create a BitmapImage from the memory stream
177-
var bitmapImage = new BitmapImage();
178-
bitmapImage.BeginInit();
179-
bitmapImage.StreamSource = memoryStream;
180-
bitmapImage.CacheOption = BitmapCacheOption.OnLoad; // Ensures full load and availability
181-
bitmapImage.EndInit();
182-
bitmapImage.Freeze(); // Makes it thread-safe and ready for WPF usage
183-
184-
return bitmapImage;
178+
using var ms = new MemoryStream();
179+
processed.Save(ms, ImageFormat.Png);
180+
ms.Position = 0;
181+
182+
var bmp = new BitmapImage();
183+
bmp.BeginInit();
184+
bmp.StreamSource = ms;
185+
bmp.CacheOption = BitmapCacheOption.OnLoad;
186+
bmp.EndInit();
187+
bmp.Freeze();
188+
189+
return bmp;
185190
}
186191
finally
187192
{
188-
tempImage?.Dispose(); // Dispose of the temporary image if created
193+
tempImage?.Dispose();
189194
}
190195
}
191-
}
196+
197+
/// <summary>
198+
/// Fasts the convert.
199+
/// </summary>
200+
/// <param name="bmp">The BMP.</param>
201+
/// <returns>BitmapImage from Bitmap.</returns>
202+
private static BitmapImage FastConvert(Bitmap bmp)
203+
{
204+
// Ensure 32bpp ARGB
205+
if (bmp.PixelFormat != System.Drawing.Imaging.PixelFormat.Format32bppArgb)
206+
{
207+
var converted = new Bitmap(bmp.Width, bmp.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
208+
using var g = Graphics.FromImage(converted);
209+
g.DrawImage(bmp, 0, 0);
210+
bmp = converted;
211+
}
212+
213+
var rect = new System.Drawing.Rectangle(0, 0, bmp.Width, bmp.Height);
214+
var bmpData = bmp.LockBits(rect, ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
215+
216+
try
217+
{
218+
// WPF erwartet Int32Rect und PixelFormats.Bgra32
219+
var wbRect = new Int32Rect(0, 0, bmp.Width, bmp.Height);
220+
221+
var wb = new WriteableBitmap(
222+
bmp.Width,
223+
bmp.Height,
224+
96, 96,
225+
PixelFormats.Bgra32,
226+
null);
227+
228+
// Verwende die IntPtr-Überladung: WritePixels(Int32Rect, IntPtr buffer, int bufferSize, int stride)
229+
wb.WritePixels(wbRect, bmpData.Scan0, Math.Abs(bmpData.Stride) * bmp.Height, Math.Abs(bmpData.Stride));
230+
wb.Freeze();
231+
232+
return WriteableBitmapToBitmapImage(wb);
233+
}
234+
finally
235+
{
236+
bmp.UnlockBits(bmpData);
237+
}
238+
}
239+
240+
/// <summary>
241+
/// Writeables the bitmap to bitmap image.
242+
/// </summary>
243+
/// <param name="wb">The wb.</param>
244+
/// <returns>BitmapImage from Bitmap.</returns>
245+
private static BitmapImage WriteableBitmapToBitmapImage(WriteableBitmap wb)
246+
{
247+
var encoder = new JpegBitmapEncoder(); // MUCH faster than PNG
248+
encoder.QualityLevel = 100; // visually lossless
249+
250+
using var ms = new MemoryStream();
251+
encoder.Frames.Add(BitmapFrame.Create(wb));
252+
encoder.Save(ms);
253+
ms.Position = 0;
254+
255+
var bmp = new BitmapImage();
256+
bmp.BeginInit();
257+
bmp.CacheOption = BitmapCacheOption.OnLoad;
258+
bmp.StreamSource = ms;
259+
bmp.EndInit();
260+
bmp.Freeze();
261+
return bmp;
262+
}
263+
}

Imaging/Interfaces/IImageRender.cs

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -252,22 +252,24 @@ Bitmap CutBitmap(Bitmap image, int width, int height, MaskShape shape, object sh
252252
/// <exception cref="IOException">Error while we try to access the File</exception>
253253
BitmapImage GetBitmapImageFileStream(string path, int width, int height);
254254

255+
255256
/// <summary>
256-
/// Converts to bitmap image.
257+
/// Bitmaps to bitmap image.
257258
/// </summary>
258-
/// <param name="image">The bitmap.</param>
259-
/// The Image as
260-
/// <see cref="BitmapImage" />
261-
/// .
259+
/// <param name="image">The image.</param>
260+
/// <param name="lossless">if set to <c>true</c> [lossless].</param>
261+
/// <returns>
262+
/// The Image as <see cref="BitmapImage" />.
263+
/// </returns>
262264
/// <exception cref="ArgumentNullException"></exception>
263-
BitmapImage BitmapToBitmapImage(Bitmap image);
265+
BitmapImage BitmapToBitmapImage(Bitmap image, bool lossless = false);
264266

265267
/// <summary>
266-
/// Bitmaps the image bitmap.
268+
/// Bitmaps the image bitmap.
267269
/// </summary>
268270
/// <param name="image">The bitmap image.</param>
269271
/// <returns>
270-
/// The Image as <see cref="Bitmap" />.
272+
/// The Image as <see cref="Bitmap" />.
271273
/// </returns>
272274
/// <exception cref="ArgumentNullException"></exception>
273275
Bitmap BitmapImageToBitmap(BitmapImage image);
@@ -574,4 +576,4 @@ Bitmap FillAreaWithColor(
574576
/// <param name="bitmapImage">The bitmap image.</param>
575577
/// <returns>Image as string</returns>
576578
string BitmapImageToBase64(BitmapImage bitmapImage);
577-
}
579+
}

0 commit comments

Comments
 (0)