原創|產品更新|編輯:李顯亮|2020-06-18 10:19:49.870|閱讀 306 次
概述: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@fc6vip.cn