120 lines
4.0 KiB
C#
120 lines
4.0 KiB
C#
using System;
|
|
namespace Quik.Media
|
|
{
|
|
public abstract class QImage : IDisposable
|
|
{
|
|
public abstract int Width { get; }
|
|
public abstract int Height { get; }
|
|
public abstract int Depth { get; }
|
|
public abstract QImageFormat InternalFormat { get; }
|
|
public virtual int MipMapLevels => 0;
|
|
public virtual bool Premultiplied => false;
|
|
public virtual bool IsSdf => false;
|
|
|
|
public abstract void LockBits2d(out QImageLock imageLock, QImageLockOptions options);
|
|
public abstract void LockBits3d(out QImageLock imageLock, QImageLockOptions options);
|
|
public abstract void LockBits3d(out QImageLock imageLock, QImageLockOptions options, int depth);
|
|
public abstract void UnlockBits();
|
|
|
|
// IDisposable
|
|
private bool isDisposed = false;
|
|
private void DisposePrivate(bool disposing)
|
|
{
|
|
if (isDisposed) return;
|
|
|
|
Dispose(disposing);
|
|
|
|
isDisposed = true;
|
|
}
|
|
protected virtual void Dispose(bool disposing) { }
|
|
public void Dispose() => DisposePrivate(true);
|
|
}
|
|
|
|
public struct QImageLockOptions
|
|
{
|
|
public QImageFormat Format { get; }
|
|
public bool Premultiply { get; }
|
|
public int MipLevel { get; }
|
|
public static QImageLockOptions Default { get; } = new QImageLockOptions(QImageFormat.RgbaU8, true, 0);
|
|
|
|
public QImageLockOptions(QImageFormat format, bool premultiply, int level)
|
|
{
|
|
Format = format;
|
|
Premultiply = premultiply;
|
|
MipLevel = level;
|
|
}
|
|
}
|
|
|
|
public struct QImageLock
|
|
{
|
|
public QImageFormat Format { get; }
|
|
public int Width { get; }
|
|
public int Height { get; }
|
|
public int Depth { get; }
|
|
public IntPtr ImagePtr { get; }
|
|
|
|
public QImageLock(QImageFormat format, int width, int height, int depth, IntPtr ptr)
|
|
{
|
|
Format = format;
|
|
Width = width;
|
|
Height = height;
|
|
Depth = depth;
|
|
ImagePtr = ptr;
|
|
}
|
|
|
|
public unsafe void CopyTo(QImageLock destination, int x, int y)
|
|
{
|
|
if (
|
|
Width + x > destination.Width ||
|
|
Height + y > destination.Height)
|
|
{
|
|
throw new Exception("Image falls outside the bounds of the destination.");
|
|
}
|
|
else if (Format != destination.Format)
|
|
{
|
|
throw new Exception("Image formats must be the same.");
|
|
}
|
|
|
|
int bpp = Format.BytesPerPixel();
|
|
for (int i = 0; i < Height; i++)
|
|
{
|
|
IntPtr srcPtr = (IntPtr)((long)ImagePtr + i * bpp);
|
|
|
|
long dstPos = x + i * destination.Width;
|
|
IntPtr dstPtr = (IntPtr)((long)destination.ImagePtr + dstPos * bpp);
|
|
|
|
Buffer.MemoryCopy((void*)srcPtr, (void*)dstPtr, Width * bpp, Width * bpp);
|
|
}
|
|
}
|
|
|
|
public unsafe void ExtractFrom(QImageLock destination, int x, int y, int width, int height)
|
|
{
|
|
if (
|
|
width != destination.Width ||
|
|
height != destination.Height)
|
|
{
|
|
throw new Exception("Destination is not the same size as the subregion.");
|
|
}
|
|
else if (x + width > Width || y + height > Height)
|
|
{
|
|
throw new Exception("The subregion is larger than this image.");
|
|
}
|
|
else if (Format != destination.Format)
|
|
{
|
|
throw new Exception("Image formats must be the same.");
|
|
}
|
|
|
|
int bpp = Format.BytesPerPixel();
|
|
for (int i = 0; i < height; i++)
|
|
{
|
|
long srcPos = x + y * i;
|
|
IntPtr srcPtr = (IntPtr)((long)ImagePtr + srcPos * bpp);
|
|
|
|
long dstPos = i * destination.Width;
|
|
IntPtr dstPtr = (IntPtr)((long)destination.ImagePtr + dstPos * bpp);
|
|
|
|
Buffer.MemoryCopy((void*)srcPtr, (void*)dstPtr, width * bpp, width * bpp);
|
|
}
|
|
}
|
|
}
|
|
} |