using System; using System.IO; using System.Runtime.InteropServices; using Quik.Media; using Quik.Media.Color; using Quik.Stb; namespace Quik.Media.Defaults { public unsafe class QImageStbi : QImage { private readonly StbImage image; private QImageBuffer buffer; 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(); buffer = new QImageBuffer(options.Format, Width, Height); buffer.LockBits2d(out QImageLock dst, QImageLockOptions.Default); 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() { buffer.UnlockBits(); } protected override void Dispose(bool disposing) { base.Dispose(disposing); if (disposing) { buffer?.Dispose(); image.Dispose(); } } } }