CPF/CPF.Skia/SkiaImage.cs

295 lines
8.7 KiB
C#
Raw Permalink Normal View History

2023-11-21 23:05:03 +08:00
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SkiaSharp;
using System.IO;
using CPF.Drawing;
namespace CPF.Skia
{
public class SkiaImage : IImageImpl
{
int frameCount;
Stream stream;
//SKBitmap[] bitmaps;
SKCodec codec;
SKBitmap bitmap;
public SkiaImage(string path)
{
stream = File.OpenRead(path);
//#if Net4
using (SKData data = SKData.Create(path))
{
codec = SKCodec.Create(data);
}
//#else
// codec = SKCodec.Create(stream);
//#endif
frameCount = Math.Max(1, codec.FrameCount);
bitmap = SKBitmap.Decode(codec);
Codec();
}
public SkiaImage(Stream stream)
{
this.stream = new MemoryStream();
stream.CopyTo(this.stream);
this.stream.Position = 0;
//#if Net4
using (SKData data = SKData.Create(this.stream))
{
codec = SKCodec.Create(data);
}
//#else
// codec = SKCodec.Create(this.stream);
//#endif
if (codec == null)
{
this.stream.Position = 0;
codec = SKCodec.Create(this.stream, out var result);
if (codec == null)
{
throw new Exception("图片解码失败" + result);
}
}
frameCount = Math.Max(1, codec.FrameCount);
bitmap = SKBitmap.Decode(codec);
Codec();
}
int[] durations;
public int[] FrameDelay { get { return durations; } }
void Codec()
{
if (frameCount > 1)
{
durations = new int[frameCount];
for (int frame = 0; frame < frameCount; frame++)
{
// From the FrameInfo collection, get the duration of each frame
durations[frame] = codec.FrameInfo[frame].Duration;
}
Duration = 0;
// Sum up the total duration
for (int frame = 0; frame < durations.Length; frame++)
{
Duration += durations[frame];
}
}
if (bitmap == null)
{
throw new Exception("图片解析失败");
}
}
//void Codec(SKCodec codec)
//{
// // Get frame count and allocate bitmaps
// frameCount = codec.FrameCount;
// if (frameCount == 0)
// {
// frameCount = 1;
// bitmaps = new SKBitmap[frameCount];
// bitmaps[0] = SKBitmap.Decode(codec);
// }
// else
// {
// bitmaps = new SKBitmap[frameCount];
// var durations = new int[frameCount];
// //var accumulatedDurations = new int[frameCount];
// // Note: There's also a RepetitionCount property of SKCodec not used here
// // Loop through the frames
// for (int frame = 0; frame < frameCount; frame++)
// {
// // From the FrameInfo collection, get the duration of each frame
// durations[frame] = codec.FrameInfo[frame].Duration;
// // Create a full-color bitmap for each frame
// SKImageInfo imageInfo = new SKImageInfo(codec.Info.Width, codec.Info.Height);
// bitmaps[frame] = new SKBitmap(imageInfo);
// // Get the address of the pixels in that bitmap
// IntPtr pointer = bitmaps[frame].GetPixels();
// // Create an SKCodecOptions value to specify the frame
// SKCodecOptions codecOptions = new SKCodecOptions(frame);
// // Copy pixels from the frame into the bitmap
// codec.GetPixels(imageInfo, pointer, codecOptions);
// }
// Duration = 0;
// // Sum up the total duration
// for (int frame = 0; frame < durations.Length; frame++)
// {
// Duration += durations[frame];
// }
// // Calculate the accumulated durations
// //for (int frame = 0; frame < durations.Length; frame++)
// //{
// // accumulatedDurations[frame] = durations[frame] +
// // (frame == 0 ? 0 : accumulatedDurations[frame - 1]);
// //}
// }
//}
public SKBitmap Image
{
get
{
if (needUpdate)
{
needUpdate = false;
IntPtr pointer = bitmap.GetPixels();
// Create an SKCodecOptions value to specify the frame
#if Net4
SKCodecOptions codecOptions = new SKCodecOptions((int)index, true);
#else
SKCodecOptions codecOptions = new SKCodecOptions((int)index, (int)index - 1);
#endif
SKImageInfo imageInfo = new SKImageInfo(codec.Info.Width, codec.Info.Height);
// Copy pixels from the frame into the bitmap
codec.GetPixels(imageInfo, pointer, codecOptions);
bitmap.NotifyPixelsChanged();
}
return bitmap;
}
}
public int Width
{
get
{
return Image.Width;
}
}
public int Height
{
get
{
return Image.Height;
}
}
public uint FrameCount
{
get
{
return (uint)frameCount;
}
}
bool needUpdate;
uint index;
public uint Index
{
get { return index; }
set
{
if (index != value)
{
index = value;
needUpdate = true;
}
}
}
~SkiaImage()
{
Dispose();
}
public int Duration { get; set; }
public void Dispose()
{
if (bitmap != null)
{
bitmap.Dispose();
bitmap = null;
}
if (codec != null)
{
codec.Dispose();
codec = null;
}
if (stream != null)
{
stream.Dispose();
stream = null;
}
GC.SuppressFinalize(this);
}
public Stream SaveToStream(ImageFormat format)
{
var f = SKEncodedImageFormat.Jpeg;
switch (format)
{
case ImageFormat.Bmp:
f = SKEncodedImageFormat.Bmp;
break;
case ImageFormat.Gif:
f = SKEncodedImageFormat.Gif;
break;
case ImageFormat.Jpeg:
f = SKEncodedImageFormat.Jpeg;
break;
case ImageFormat.Png:
f = SKEncodedImageFormat.Png;
break;
default:
break;
}
using (var image = SKImage.FromBitmap(Image))
{
var data = image.Encode(f, 100);
var d = data.AsStream();
return d;
}
}
public void SaveToStream(ImageFormat format, Stream m)
{
var f = SKEncodedImageFormat.Jpeg;
switch (format)
{
case ImageFormat.Bmp:
f = SKEncodedImageFormat.Bmp;
break;
case ImageFormat.Gif:
f = SKEncodedImageFormat.Gif;
break;
case ImageFormat.Jpeg:
f = SKEncodedImageFormat.Jpeg;
break;
case ImageFormat.Png:
f = SKEncodedImageFormat.Png;
break;
default:
break;
}
using (var image = SKImage.FromBitmap(Image))
{
var data = image.Encode(f, 100);
//var d = data.AsStream();
//return d;
data.SaveTo(m);
data.Dispose();
}
}
public object Clone()
{
stream.Position = 0;
return new SkiaImage(stream);
}
}
}