MagicScaler是一个专为.NET平台设计的高性能图像处理库,其核心目标是让复杂的图像处理任务变得简单易行。它采用业界领先的算法,以线性光处理和锐化技术提供顶级的缩放质量。在速度与效率方面,MagicScaler在.NET生态中独领风骚。
适用业务场景:
1、快速且高质量地将大尺寸图片转换成适合网页显示的小图。
2、适应各种社交媒体平台的图像尺寸要求,自动调整图片大小并保持清晰度。
3、对于内存和计算资源有限的设备,MagicScaler可以有效减小图像处理的负担。
4、大量图片的自动化处理,如图片格式转换,尺寸调整等。
如下所示是用于接收字节大尺寸图片后进行缩放处理的方法:
using PhotoSauce.MagicScaler;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
namespace CentralizedDisplayDemo.TCPCcd
{
/// <summary>
/// CCD图像处理与信息绘制(PhotoSauce MagicScaler高性能版本)
/// </summary>
public class PhotoSauceImage : IDisposable
{
private bool _disposed;
// 缓存GDI+资源
private readonly Font _titleFont;
private readonly Font _normalFont;
private readonly Font _largeFont;
private const int PEN_WIDTH = 1;
private const int BRIGHTNESS_CIRCLE_RADIUS = 40;
private const int TEXT_OFFSET_X = 100;
private const int TEXT_OFFSET_Y_BASE = 50;
private const int TEXT_LINE_SPACING = 150;
private readonly SolidBrush _redBrush;
private readonly SolidBrush _blueBrush;
private readonly SolidBrush _lightBlueBrush;
private readonly Pen _greenPen;
private readonly Pen _redPen;
private readonly Pen _arrowPen;
private float _scale = 0.2f;
private static int _imageWidth = 2048;
private static int _imageHeight = 1500;
/// <summary>
/// 高质量配置(最佳清晰度,适合最终输出)
/// 使用 Lanczos 算法 + 自动锐化
/// </summary>
private static readonly ProcessImageSettings _highQualitySettings = new ProcessImageSettings
{
Width = _imageWidth,
Height = _imageHeight,
ResizeMode = CropScaleMode.Stretch,
Interpolation = InterpolationSettings.Lanczos, // 最高质量,适合照片缩放
Sharpen = true, // 启用自动锐化补偿
ColorProfileMode = ColorProfileMode.Normalize,
HybridMode = HybridScaleMode.FavorQuality
};
/// <summary>
/// 平衡配置(质量与性能的折中)
/// 使用 Mitchell 算法,比 Lanczos 快约 30%,质量接近
/// </summary>
private static readonly ProcessImageSettings _balancedSettings = new ProcessImageSettings
{
Width = _imageWidth,
Height = _imageHeight,
ResizeMode = CropScaleMode.Stretch,
Interpolation = InterpolationSettings.Mitchell, // Mitchell-Netravali,高质量
Sharpen = true,
ColorProfileMode = ColorProfileMode.Normalize,
HybridMode = HybridScaleMode.FavorQuality
};
/// <summary>
/// 高性能配置(优先速度,适合实时预览)
/// 使用 CatmullRom/Cubic 算法,速度快,质量尚可
/// </summary>
private static readonly ProcessImageSettings _fastSettings = new ProcessImageSettings
{
Width = _imageWidth,
Height = _imageHeight,
ResizeMode = CropScaleMode.Stretch,
Interpolation = InterpolationSettings.Cubic, // 双三次插值,速度快
Sharpen = false, // 关闭锐化提升速度
ColorProfileMode = ColorProfileMode.Normalize,
HybridMode = HybridScaleMode.FavorSpeed
};
/// <summary>
/// 极限速度配置(最低延迟,适合4帧/秒以上实时流)
/// 使用 Linear/Bilinear 算法,牺牲质量换取速度
/// </summary>
private static readonly ProcessImageSettings _ultraFastSettings = new ProcessImageSettings
{
Width = _imageWidth,
Height = _imageHeight,
ResizeMode = CropScaleMode.Stretch,
Interpolation = InterpolationSettings.Linear, // 双线性插值,最快
Sharpen = false,
ColorProfileMode = ColorProfileMode.Normalize,
HybridMode = HybridScaleMode.FavorSpeed
};
public PhotoSauceImage()
{
_titleFont = new Font("宋体", 14, FontStyle.Bold);
_normalFont = new Font("宋体", 14, FontStyle.Bold);
_largeFont = new Font("宋体", 60, FontStyle.Bold);
_redBrush = new SolidBrush(Color.Crimson);
_blueBrush = new SolidBrush(Color.Tomato);
_lightBlueBrush = new SolidBrush(Color.LightBlue);
_greenPen = new Pen(Color.Lime, PEN_WIDTH);
_redPen = new Pen(Color.Crimson, PEN_WIDTH);
_arrowPen = new Pen(Color.Crimson, 1);
_arrowPen.CustomEndCap = new AdjustableArrowCap(2, 2);
}
/// <summary>
/// 高质量版本(推荐日常使用)
/// 清晰度:★★★★★ 性能:★★★★
/// </summary>
public Bitmap ConvertBytesToBitmapHighQuality(byte[] imageBytes, ROIModel roi)
{
return ProcessImage(imageBytes, roi, _highQualitySettings);
}
/// <summary>
/// 平衡版本(推荐实时显示)
/// 清晰度:★★★★ 性能:★★★★★
/// </summary>
public Bitmap ConvertBytesToBitmapBalanced(byte[] imageBytes, ROIModel roi)
{
return ProcessImage(imageBytes, roi, _balancedSettings);
}
/// <summary>
/// 快速版本(高帧率场景,4帧/秒以上)
/// 清晰度:★★★ 性能:★★★★★
/// </summary>
public Bitmap ConvertBytesToBitmapFast(byte[] imageBytes, ROIModel roi)
{
return ProcessImage(imageBytes, roi, _fastSettings);
}
/// <summary>
/// 极限速度版本(8帧/秒以上)
/// 清晰度:★★ 性能:★★★★★
/// </summary>
public Bitmap ConvertBytesToBitmapUltraFast(byte[] imageBytes, ROIModel roi)
{
return ProcessImage(imageBytes, roi, _ultraFastSettings);
}
/// <summary>
/// 核心处理方法
/// </summary>
private Bitmap ProcessImage(byte[] imageBytes, ROIModel roi, ProcessImageSettings settings)
{
if (imageBytes == null || imageBytes.Length == 0)
{
throw new ArgumentNullException(nameof(imageBytes));
}
using (var inputStream = new MemoryStream(imageBytes))
using (var outputStream = new MemoryStream())
{
// MagicScaler 解码并缩放
MagicImageProcessor.ProcessImage(inputStream, outputStream, settings);
outputStream.Seek(0, SeekOrigin.Begin);
using (var scaledImage = Image.FromStream(outputStream))
{
_scale = (float)scaledImage.Width / 4096;
_imageWidth = scaledImage.Width;
_imageHeight = scaledImage.Height;
var resultBitmap = new Bitmap(_imageWidth, _imageHeight, PixelFormat.Format24bppRgb);
using (var graphics = Graphics.FromImage(resultBitmap))
{
graphics.CompositingQuality = CompositingQuality.HighSpeed;
graphics.InterpolationMode = InterpolationMode.NearestNeighbor;
graphics.PixelOffsetMode = PixelOffsetMode.None;
graphics.SmoothingMode = SmoothingMode.HighSpeed;
graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.SingleBitPerPixel;
graphics.DrawImage(scaledImage, 0, 0, _imageWidth, _imageHeight);
if (roi != null)
{
graphics.SmoothingMode = SmoothingMode.AntiAlias;
DrawROI(graphics, roi);
DrawResults(graphics, roi);
DrawTextInfo(graphics, roi);
graphics.SmoothingMode = SmoothingMode.HighSpeed;
}
}
return resultBitmap;
}
}
}
/// <summary>
/// 兼容原有接口(默认使用平衡配置)
/// </summary>
public async Task<Bitmap> ConvertBytesToBitmapAsync(byte[] imageBytes, ROIModel roi)
{
return await Task.Run(() => ConvertBytesToBitmapHighQuality(imageBytes, roi));
}
#region 绘制方法
private void DrawROI(Graphics graphics, ROIModel roi)
{
var step = roi.ParseInt("ss", 0);
var status = roi.ParseInt("ss", 1);
var x1 = roi.ParseInt("mm", 0) * _scale;
var y1 = roi.ParseInt("mm", 1) * _scale;
var x2 = roi.ParseInt("mm", 2) * _scale;
var y2 = roi.ParseInt("mm", 3) * _scale;
var x3 = roi.ParseInt("mm", 4) * _scale;
var y3 = roi.ParseInt("mm", 5) * _scale;
var x4 = roi.ParseInt("mm", 6) * _scale;
var y4 = roi.ParseInt("mm", 7) * _scale;
if (step != 23 && x3 > 0 && y3 > 0)
{
graphics.DrawLine(_redPen, x1, y1, x2, y2);
graphics.DrawLine(_greenPen, x3, y3, x4, y4);
graphics.DrawLine(_arrowPen, x1, y1, x3, y3);
DrawVerticalLine(graphics, _redPen, x3, y3, 4);
graphics.DrawLine(_arrowPen, x2, y2, x4, y4);
DrawVerticalLine(graphics, _redPen, x4, y4, 4);
}
if (status == 3)
{
DrawDiametricLines(graphics, roi);
}
else
{
DrawSeedCrystalRect(graphics, roi);
}
}
private void DrawVerticalLine(Graphics g, Pen pen, float centerX, float centerY, float height)
{
float halfHeight = height / 2f;
g.DrawLine(pen, centerX, centerY - halfHeight, centerX, centerY + halfHeight);
}
private void DrawDiametricLines(Graphics graphics, ROIModel roi)
{
graphics.DrawLine(_greenPen,
roi.ParseInt("bm", 0) * _scale, roi.ParseInt("bm", 1) * _scale,
roi.ParseInt("bm", 2) * _scale, roi.ParseInt("bm", 3) * _scale);
graphics.DrawLine(_redPen,
roi.ParseInt("bm", 4) * _scale, roi.ParseInt("bm", 5) * _scale,
roi.ParseInt("bm", 6) * _scale, roi.ParseInt("bm", 7) * _scale);
graphics.DrawLine(_greenPen,
roi.ParseInt("bm", 8) * _scale, roi.ParseInt("bm", 9) * _scale,
roi.ParseInt("bm", 10) * _scale, roi.ParseInt("bm", 11) * _scale);
graphics.DrawLine(_redPen,
roi.ParseInt("bm", 12) * _scale, roi.ParseInt("bm", 13) * _scale,
roi.ParseInt("bm", 14) * _scale, roi.ParseInt("bm", 15) * _scale);
}
private void DrawSeedCrystalRect(Graphics graphics, ROIModel roi)
{
int x1 = (int)(roi.ParseInt("sm", 0) * _scale);
int y1 = (int)(roi.ParseInt("sm", 1) * _scale);
int x2 = (int)(roi.ParseInt("sm", 2) * _scale);
int y2 = (int)(roi.ParseInt("sm", 3) * _scale);
int x3 = (int)(roi.ParseInt("sm", 4) * _scale);
int y3 = (int)(roi.ParseInt("sm", 5) * _scale);
int x4 = (int)(roi.ParseInt("sm", 6) * _scale);
int y4 = (int)(roi.ParseInt("sm", 7) * _scale);
int heighty = y1 + Math.Abs(y1 - y2) / 2;
int width = Math.Abs(x1 - x2);
int height = Math.Abs(y1 - y2);
graphics.DrawRectangle(_greenPen, x1, y1, width, height);
graphics.DrawLine(_redPen, x1, heighty, x3, heighty);
graphics.DrawLine(_redPen, x4, heighty, x1 + width, heighty);
graphics.DrawLine(_redPen, x3, y1, x3, y1 + height);
graphics.DrawLine(_redPen, x4, y1, x4, y1 + height);
}
private void DrawResults(Graphics graphics, ROIModel roi)
{
int brightnessX = roi.ParseInt("br", 0);
int brightnessY = roi.ParseInt("br", 1);
float radius = BRIGHTNESS_CIRCLE_RADIUS * _scale;
graphics.DrawEllipse(_redPen,
brightnessX * _scale - radius,
brightnessY * _scale - radius,
radius * 2, radius * 2);
}
private void DrawTextInfo(Graphics graphics, ROIModel roi)
{
float yPos = TEXT_OFFSET_Y_BASE * _scale;
float xOffset = TEXT_OFFSET_X * _scale;
graphics.DrawString($"直径: {roi.SD[3]}pix/{roi.SD[4]}mm", _titleFont, _redBrush, xOffset, yPos);
yPos += TEXT_LINE_SPACING * _scale;
graphics.DrawString($"液口距: {roi.SD[5]}pix/{roi.SD[6]}mm", _titleFont, _redBrush, xOffset, yPos);
yPos += TEXT_LINE_SPACING * _scale;
graphics.DrawString($"亮度: {roi.SD[0]}", _titleFont, _redBrush, xOffset, yPos);
yPos += TEXT_LINE_SPACING * _scale;
graphics.DrawString(roi.SD[1], _normalFont, _lightBlueBrush, 3400 * _scale, 2800 * _scale);
graphics.DrawString(roi.SD[2], _largeFont, _blueBrush, TEXT_OFFSET_X * _scale, 600 * _scale);
DrawStatusInfo(graphics, roi);
}
private void DrawStatusInfo(Graphics graphics, ROIModel roi)
{
int step = roi.ParseInt("ss", 0);
float yPos = TEXT_OFFSET_Y_BASE * _scale;
float xOffset = 2600 * _scale;
if (step == 8 || step == 9)
{
graphics.DrawString($"结晶检测: {roi.SD[7]}", _titleFont, _redBrush, xOffset, yPos);
yPos += TEXT_LINE_SPACING * _scale;
}
if (step == 24 || step == 4)
{
graphics.DrawString("MLD实时:35.5", _titleFont, _redBrush, xOffset, yPos);
}
else
{
graphics.DrawString("MLD均值:35.5", _titleFont, _redBrush, xOffset, yPos);
}
}
#endregion
public void Dispose()
{
if (_disposed) return;
_titleFont?.Dispose();
_normalFont?.Dispose();
_largeFont?.Dispose();
_redBrush?.Dispose();
_blueBrush?.Dispose();
_lightBlueBrush?.Dispose();
_greenPen?.Dispose();
_redPen?.Dispose();
_arrowPen?.Dispose();
_disposed = true;
GC.SuppressFinalize(this);
}
~PhotoSauceImage()
{
Dispose();
}
}
}