2023-07-09 16:46:35 +02:00
|
|
|
using System;
|
|
|
|
using System.IO;
|
|
|
|
using System.Runtime.InteropServices;
|
|
|
|
using Quik.Media;
|
|
|
|
using Quik.Media.Color;
|
|
|
|
using Quik.Stb;
|
|
|
|
|
2023-09-16 08:50:14 +02:00
|
|
|
namespace Quik.Media.Defaults
|
2023-07-09 16:46:35 +02:00
|
|
|
{
|
|
|
|
public unsafe class QImageStbi : QImage
|
|
|
|
{
|
|
|
|
private readonly StbImage image;
|
2023-09-22 18:30:17 +02:00
|
|
|
private QImageBuffer buffer;
|
2023-07-09 16:46:35 +02:00
|
|
|
|
|
|
|
public override int Width => image.Width;
|
|
|
|
|
|
|
|
public override int Height => image.Height;
|
|
|
|
|
|
|
|
public override int Depth => 1;
|
|
|
|
public override QImageFormat InternalFormat => Stb2QImageFormat(image.Format);
|
|
|
|
|
|
|
|
public QImageStbi(Stream source)
|
|
|
|
{
|
|
|
|
// According to the stbi documentation, only a specific type of PNG
|
|
|
|
// files are premultiplied out of the box (iPhone PNG). Take the
|
|
|
|
// precision loss L and move on.
|
|
|
|
StbImage.FlipVerticallyOnLoad = true;
|
|
|
|
StbImage.UnpremultiplyOnLoad = true;
|
|
|
|
|
|
|
|
image = StbImage.Load(source);
|
|
|
|
}
|
|
|
|
|
|
|
|
public static QImageFormat Stb2QImageFormat(StbiImageFormat src)
|
|
|
|
{
|
|
|
|
switch (src)
|
|
|
|
{
|
|
|
|
case StbiImageFormat.Grey: return QImageFormat.RedU8;
|
|
|
|
case StbiImageFormat.Rgb: return QImageFormat.RgbU8;
|
|
|
|
case StbiImageFormat.Rgba: return QImageFormat.RgbaU8;
|
|
|
|
case StbiImageFormat.GreyAlpha: return QImageFormat.RaU8;
|
|
|
|
default: return QImageFormat.Undefined;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public override void LockBits2d(out QImageLock imageLock, QImageLockOptions options)
|
|
|
|
{
|
|
|
|
if (options.MipLevel > 0) throw new Exception("This image has no mip levels.");
|
|
|
|
|
|
|
|
buffer?.Dispose();
|
2023-09-22 18:30:17 +02:00
|
|
|
buffer = new QImageBuffer(options.Format, Width, Height);
|
|
|
|
buffer.LockBits2d(out QImageLock dst, QImageLockOptions.Default);
|
2023-07-09 16:46:35 +02:00
|
|
|
|
|
|
|
byte *srcPtr = (byte*)image.ImagePointer;
|
|
|
|
QImageLock src = new QImageLock(InternalFormat, Width, Height, 1, (IntPtr)srcPtr);
|
|
|
|
FormatConvert.Convert(dst, src);
|
|
|
|
|
|
|
|
if (options.Premultiply)
|
|
|
|
{
|
|
|
|
FormatConvert.Premultiply(dst);
|
|
|
|
}
|
|
|
|
|
|
|
|
imageLock = dst;
|
|
|
|
}
|
|
|
|
|
|
|
|
public override void LockBits3d(out QImageLock imageLock, QImageLockOptions options)
|
|
|
|
{
|
|
|
|
LockBits2d(out imageLock, options);
|
|
|
|
}
|
|
|
|
|
|
|
|
public override void LockBits3d(out QImageLock imageLock, QImageLockOptions options, int depth)
|
|
|
|
{
|
|
|
|
if (depth != 1) throw new ArgumentOutOfRangeException(nameof(depth));
|
|
|
|
|
|
|
|
LockBits2d(out imageLock, options);
|
|
|
|
}
|
|
|
|
|
|
|
|
public override void UnlockBits()
|
|
|
|
{
|
2023-09-22 18:30:17 +02:00
|
|
|
buffer.UnlockBits();
|
2023-07-09 16:46:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
protected override void Dispose(bool disposing)
|
|
|
|
{
|
|
|
|
base.Dispose(disposing);
|
|
|
|
|
|
|
|
if (disposing)
|
|
|
|
{
|
|
|
|
buffer?.Dispose();
|
|
|
|
image.Dispose();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|