using System; using System.Runtime.InteropServices; namespace Quik.Media { public class QImageBuffer : QImage { private byte[] buffer; GCHandle handle; public override QImageFormat InternalFormat { get; } public override int Width { get; } public override int Height { get; } public override int Depth { get; } public QImageBuffer(QImageFormat format, int width, int height, int depth = 1) { InternalFormat = format; Width = width; Height = height; Depth = depth; buffer = new byte[width * height * depth * format.BytesPerPixel()]; } ~QImageBuffer() { Dispose(false); } private QImageLock Lock() { handle.Free(); handle = GCHandle.Alloc(buffer, GCHandleType.Pinned); IntPtr ptr = Marshal.UnsafeAddrOfPinnedArrayElement(buffer, 0); return new QImageLock(InternalFormat, Width, Height, Depth, ptr); } protected override void Dispose(bool disposing) { if (handle.IsAllocated) handle.Free(); buffer = null; GC.SuppressFinalize(this); } public override void LockBits2d(out QImageLock imageLock, QImageLockOptions options) { if (options.Format != options.Format) throw new InvalidOperationException("This image type cannot be converted."); if (Depth > 1) throw new InvalidOperationException("This texture has a depth component."); UnlockBits(); handle = GCHandle.Alloc(buffer, GCHandleType.Pinned); IntPtr ptr = Marshal.UnsafeAddrOfPinnedArrayElement(buffer, 0); imageLock = new QImageLock(InternalFormat, Width, Height, Depth, ptr); } public override void LockBits3d(out QImageLock imageLock, QImageLockOptions options) { if (options.Format != options.Format) throw new InvalidOperationException("This image type cannot be converted."); UnlockBits(); handle = GCHandle.Alloc(buffer, GCHandleType.Pinned); IntPtr ptr = Marshal.UnsafeAddrOfPinnedArrayElement(buffer, 0); imageLock = new QImageLock(InternalFormat, Width, Height, Depth, ptr); } public override void LockBits3d(out QImageLock imageLock, QImageLockOptions options, int depth) { if (options.Format != options.Format) throw new InvalidOperationException("This image type cannot be converted."); if (depth < 0 || depth > Depth) throw new ArgumentOutOfRangeException(nameof(depth), "Depth must be in range."); UnlockBits(); handle = GCHandle.Alloc(buffer, GCHandleType.Pinned); IntPtr ptr = Marshal.UnsafeAddrOfPinnedArrayElement(buffer, 0); imageLock = new QImageLock( InternalFormat, Width, Height, 1, ptr + (depth * Width * Height * InternalFormat.BytesPerPixel())); } public override void UnlockBits() { if (handle.IsAllocated) handle.Free(); } } }