原创|产品更新|编辑:李显亮|2020-06-18 10:19:49.870|阅读 226 次
概述:Aspose.Imaging for .NET更新至最新版v20.6,支持APNG(动画PNG)文件格式,支持BMP的新压缩方法DXT1 ,支持批量导出到WebP以获得多页图像,欢迎下载体验。
# 慧都年终大促·界面/图表报表/文档/IDE等千款热门软控件火热促销中 >>
Aspose.Imaging for .NET一种高级图像处理控件,允许开发人员创建,编辑,绘制或转换图像。图像导出和转换是API核心功能之一,它允许在不安装Photoshop应用程序或任何其他图像编辑器的情况下保存为AdobePhotoshop®本机格式。
事实证明,Aspose.Imaging是处理各种图像格式的强大API。除单页图像外,Aspose.Imaging还支持处理多页图像,包括GIF,TIFF,PSD,DICOM,CDR和WebP。
近期发布了Aspose.Imaging for .NET v20.6,支持APNG(动画PNG)文件格式,支持BMP的新压缩方法DXT1 ,支持批量导出到WebP以获得多页图像,还没使用过的朋友可以点击下载最新版Aspose.Imaging
key | 概述 | 类别 |
---|---|---|
IMAGINGNET-3618 | 实现对APNG(动画PNG)文件格式的支持 | 功能 |
IMAGINGNET-3849 | 支持BMP的新压缩方法DXT1 | 功能 |
IMAGINGNET-3781 | 支持批量导出到WebP以获得多页图像 | 功能 |
IMAGINGNET-3882 | 无法从XMP元数据提取Azure标签信息 | 增强功能 |
IMAGINGNET-3804 | 将WMF保存为PNG时形状崩溃 | 增强功能 |
创建图像并设置其像素。
// Example 1. Creating an image and setting its pixels. using System.Diagnostics; using Aspose.Imaging; using Aspose.Imaging.ImageOptions; using Aspose.Imaging.FileFormats.Png; using Aspose.Imaging.FileFormats.Apng; // Load pixels from source raster image Size imageSize; int[] imagePixels; using (RasterImage sourceImage = (RasterImage)Image.Load("not_animated.png")) { imageSize = sourceImage.Size; imagePixels = sourceImage.LoadArgb32Pixels(sourceImage.Bounds); } // Create APNG image and set its pixels using (ApngImage image = (ApngImage)Image.Create( new ApngOptions() { Source = new FileCreateSource("created_apng.png", false), ColorType = PngColorType.TruecolorWithAlpha }, imageSize.Width, imageSize.Height)) { image.SaveArgb32Pixels(image.Bounds, imagePixels); image.Save(); } // Check output file format using (Image image = Image.Load("created_apng.png")) { Debug.Assert(image.FileFormat == FileFormat.Apng); Debug.Assert(image is ApngImage); }
栅格图像操作
// The brightness adjustment operation using Aspose.Imaging; using Aspose.Imaging.FileFormats.Apng; using (ApngImage image = (ApngImage)Image.Load("elephant.png")) { image.AdjustBrightness(100); image.Save("AdjustBrightness.png"); }
从另一个单页图像创建动画图像
// Create an animated image from another single-page image using Aspose.Imaging; using Aspose.Imaging.ImageOptions; using Aspose.Imaging.FileFormats.Apng; const int AnimationDuration = 1000; // 1 s const int FrameDuration = 70; // 70 ms using (RasterImage sourceImage = (RasterImage)Image.Load("not_animated.png")) { ApngOptions createOptions = new ApngOptions { Source = new FileCreateSource("raster_animation.png", false), DefaultFrameTime = (uint)FrameDuration, ColorType = PngColorType.TruecolorWithAlpha, }; using (ApngImage apngImage = (ApngImage)Image.Create( createOptions, sourceImage.Width, sourceImage.Height)) { int numOfFrames = AnimationDuration / FrameDuration; int numOfFrames2 = numOfFrames / 2; apngImage.RemoveAllFrames(); // add first frame apngImage.AddFrame(sourceImage, FrameDuration); // add intermediate frames for (int frameIndex = 1; frameIndex < numOfFrames - 1; ++frameIndex) { apngImage.AddFrame(sourceImage, FrameDuration); ApngFrame lastFrame = (ApngFrame)apngImage.Pages[apngImage.PageCount - 1]; float gamma = frameIndex >= numOfFrames2 ? numOfFrames - frameIndex - 1 : frameIndex; lastFrame.AdjustGamma(gamma); } // add last frame apngImage.AddFrame(sourceImage, FrameDuration); apngImage.Save(); } }
根据矢量图形操作创建APNG动画
// Create APNG animation based on vector graphics operations using Aspose.Imaging; using Aspose.Imaging.FileFormats.Apng; // preparing the animation scene const int SceneWidth = 400; const int SceneHeigth = 400; const uint ActDuration = 1000; // Act duration, in milliseconds const uint TotalDuration = 4000; // Total duration, in milliseconds const uint FrameDuration = 50; // Frame duration, in milliseconds Scene scene = new Scene(); Ellipse ellipse = new Ellipse { FillColor = Color.FromArgb(128, 128, 128), CenterPoint = new PointF(SceneWidth / 2f, SceneHeigth / 2f), RadiusX = 80, RadiusY = 80 }; scene.AddObject(ellipse); Line line = new Line { Color = Color.Blue, LineWidth = 10, StartPoint = new PointF(30, 30), EndPoint = new PointF(SceneWidth - 30, 30) }; scene.AddObject(line); IAnimation lineAnimation1 = new LinearAnimation( delegate(float progress) { line.StartPoint = new PointF( 30 + (progress * (SceneWidth - 60)), 30 + (progress * (SceneHeigth - 60))); line.Color = Color.FromArgb( (int)(progress * 255), 0, 255 - (int)(progress * 255)); }) { Duration = ActDuration }; IAnimation lineAnimation2 = new LinearAnimation( delegate(float progress) { line.EndPoint = new PointF( SceneWidth - 30 - (progress * (SceneWidth - 60)), 30 + (progress * (SceneHeigth - 60))); line.Color = Color.FromArgb( 255, (int)(progress * 255), 0); }) { Duration = ActDuration }; IAnimation lineAnimation3 = new LinearAnimation( delegate(float progress) { line.StartPoint = new PointF( SceneWidth - 30 - (progress * (SceneWidth - 60)), SceneHeigth - 30 - (progress * (SceneHeigth - 60))); line.Color = Color.FromArgb( 255 - (int)(progress * 255), 255, 0); }) { Duration = ActDuration }; IAnimation lineAnimation4 = new LinearAnimation( delegate(float progress) { line.EndPoint = new PointF( 30 + (progress * (SceneWidth - 60)), SceneHeigth - 30 - (progress * (SceneHeigth - 60))); line.Color = Color.FromArgb( 0, 255 - (int)(progress * 255), (int)(progress * 255)); }) { Duration = ActDuration }; IAnimation fullLineAnimation = new SequentialAnimation() { lineAnimation1, lineAnimation2, lineAnimation3, lineAnimation4 }; IAnimation ellipseAnimation1 = new LinearAnimation( delegate(float progress) { ellipse.RadiusX += progress * 10; ellipse.RadiusY += progress * 10; int compValue = (int)(128 + (progress * 112)); ellipse.FillColor = Color.FromArgb( compValue, compValue, compValue); }) { Duration = ActDuration }; IAnimation ellipseAnimation2 = new Delay() { Duration = ActDuration }; IAnimation ellipseAnimation3 = new LinearAnimation( delegate(float progress) { ellipse.RadiusX -= progress * 10; int compValue = (int)(240 - (progress * 224)); ellipse.FillColor = Color.FromArgb( compValue, compValue, compValue); }) { Duration = ActDuration }; IAnimation ellipseAnimation4 = new LinearAnimation( delegate(float progress) { ellipse.RadiusY -= progress * 10; int compValue = (int)(16 + (progress * 112)); ellipse.FillColor = Color.FromArgb( compValue, compValue, compValue); }) { Duration = ActDuration }; IAnimation fullEllipseAnimation = new SequentialAnimation() { ellipseAnimation1, ellipseAnimation2, ellipseAnimation3, ellipseAnimation4 }; scene.Animation = new ParallelAnimation() { fullLineAnimation, fullEllipseAnimation }; // playing the scene on the newly created ApngImage ApngOptions createOptions = new ApngOptions { Source = new FileCreateSource("vector_animation.png", false), ColorType = PngColorType.TruecolorWithAlpha, }; using (ApngImage image = (ApngImage)Image.Create(createOptions, SceneWidth, SceneHeigth)) { image.DefaultFrameTime = FrameDuration; scene.Play(image, TotalDuration); image.Save(); } /////////////////////////// Scene.cs ///////////////////////////// using System.Collections.Generic; using Aspose.Imaging.FileFormats.Apng; using Graphics = Aspose.Imaging.Graphics; // The graphics scene public class Scene { private readonly ListgraphicsObjects = new List(); public IAnimation Animation { get; set; } public void AddObject(IGraphicsObject graphicsObject) { this.graphicsObjects.Add(graphicsObject); } public void Play(ApngImage animationImage, uint totalDuration) { uint frameDuration = animationImage.DefaultFrameTime; uint numFrames = totalDuration / frameDuration; uint totalElapsed = 0; for (uint frameIndex = 0; frameIndex < numFrames; frameIndex++) { if (this.Animation != null) { this.Animation.Update(totalElapsed); } ApngFrame frame = animationImage.PageCount == 0 || frameIndex > 0 ? animationImage.AddFrame() : (ApngFrame)animationImage.Pages[0]; Graphics graphics = new Graphics(frame); graphics.SmoothingMode = SmoothingMode.AntiAlias; foreach (IGraphicsObject graphicsObject in this.graphicsObjects) { graphicsObject.Render(graphics); } totalElapsed += frameDuration; } } } /////////////////////////// IGraphicsObject.cs ///////////////////////////// using Graphics = Aspose.Imaging.Graphics; // The graphics object public interface IGraphicsObject { void Render(Graphics graphics); } /////////////////////////// Line.cs ///////////////////////////// using Graphics = Aspose.Imaging.Graphics; // The line public class Line : IGraphicsObject { public PointF StartPoint { get; set; } public PointF EndPoint { get; set; } public float LineWidth { get; set; } public Color Color { get; set; } public void Render(Graphics graphics) { graphics.DrawLine(new Pen(this.Color, this.LineWidth), this.StartPoint, this.EndPoint); } } /////////////////////////// Ellipse.cs ///////////////////////////// using Aspose.Imaging.Brushes; using Graphics = Aspose.Imaging.Graphics; // The ellipse public class Ellipse : IGraphicsObject { public Color FillColor { get; set; } public PointF CenterPoint { get; set; } public float RadiusX { get; set; } public float RadiusY { get; set; } public void Render(Graphics graphics) { graphics.FillEllipse( new SolidBrush(this.FillColor), this.CenterPoint.X - this.RadiusX, this.CenterPoint.Y - this.RadiusY, this.RadiusX * 2, this.RadiusY * 2); } } /////////////////////////// IAnimation.cs ///////////////////////////// // The animation public interface IAnimation { // The animation duration, in milliseconds. uint Duration { get; set; } void Update(uint elapsed); } /////////////////////////// LinearAnimation.cs ///////////////////////////// // The linear animation public class LinearAnimation : IAnimation { private readonly AnimationProgressHandler progressHandler; public delegate void AnimationProgressHandler(float progress); public LinearAnimation(AnimationProgressHandler progressHandler) { if (progressHandler == null) { throw new System.ArgumentNullException("progressHandler"); } this.progressHandler = progressHandler; } public uint Duration { get; set; } public void Update(uint elapsed) { if (elapsed <= this.Duration) { this.progressHandler.Invoke((float)elapsed / this.Duration); } } } /////////////////////////// Delay.cs ///////////////////////////// // The simple delay between other animations public class Delay : IAnimation { public uint Duration { get; set; } public void Update(uint elapsed) { // nop } } /////////////////////////// ParallelAnimation.cs ///////////////////////////// using System.Collections.Generic; // The parallel animation processor public class ParallelAnimation : List, IAnimation { public uint Duration { get { uint maxDuration = 0; foreach (IAnimation animation in this) { if (maxDuration < animation.Duration) { maxDuration = animation.Duration; } } return maxDuration; } set { throw new System.NotSupportedException(); } } public void Update(uint elapsed) { foreach (IAnimation animation in this) { animation.Update(elapsed); } } } /////////////////////////// SequentialAnimation.cs ///////////////////////////// using System.Collections.Generic; // The sequential animation processor public class SequentialAnimation : List, IAnimation { public uint Duration { get { uint summDuration = 0; foreach (IAnimation animation in this) { summDuration += animation.Duration; } return summDuration; } set { throw new System.NotSupportedException(); } } public void Update(uint elapsed) { uint totalDuration = 0; foreach (IAnimation animation in this) { if (totalDuration > elapsed) { break; } animation.Update(elapsed - totalDuration); totalDuration += animation.Duration; } } }
using (TiffImage tiffImage = (TiffImage)Image.Load("10MB_Tif.tif")) { // Set batch operation for pages tiffImage.PageExportingAction = delegate(int index, Image page) { // Fires garbage collection to avoid unnecessary garbage storage from previous pages GC.Collect(); ((RasterImage)page).Rotate(90); }; tiffImage.Save("rotated.webp", new WebPOptions()); /* Attention! In batch mode all pages will be released in this line! If you want to further perform operations on the original image, you should reload it from the source to another instance. */ }
DXT1压缩
DXTn是一组相关的有损纹理压缩算法。该算法有五种变体(命名为DXT1至DXT5),每种变体均针对特定类型的图像数据而设计。全部将4X4像素块转换为64位或128位量,对于24位RGB输入数据,压缩率为6:1;对于32位RGBA输入数据,压缩率为4:1。它包含在Microsoft的DirectX 6.0和OpenGL 1.3中,导致该技术在硬件和软件制造商中得到广泛采用。
DXT1算法
DXT1(也称为块压缩1或BC1)是最简单的压缩,也是其他类型DXT算法的基础。它是DXT的最小变体,在64位输出中存储16个输入像素,包括两个16位颜色值和一个4X4 2位查找表。颜色信息也以压缩方式存储,因此每种颜色仅使用16位。这意味着纹理的这16个像素仅占用64位(调色板使用32位,索引使用32位)。那是1:8的压缩比。
如何使用DXT1压缩
以下代码演示了如何使用DXT1压缩来压缩现有图像:
using (var image = Image.Load("Tiger.bmp")) { image.Save("CompressedTiger.bmp", new BmpOptions { Compression = BitmapCompression.Dxt1 }); }
如何解压缩图像
以下代码显示了如何解压缩先前压缩的图像:
using (var image = Image.Load("CompressedTiger.bmp")) { image.Save("DecompressedTiger.bmp", new BmpOptions()); }
本站文章除注明转载外,均为本站原创或翻译。欢迎任何形式的转载,但请务必注明出处、不得修改原文相关链接,如果存在内容上的异议请邮件反馈至chenjj@cahobeh.cn