Skip to content

Instantly share code, notes, and snippets.

@KelsonBall
Created September 4, 2017 19:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save KelsonBall/c1c86b9d4a3db12d70d922716c43180f to your computer and use it in GitHub Desktop.
Save KelsonBall/c1c86b9d4a3db12d70d922716c43180f to your computer and use it in GitHub Desktop.
using System;
using System.IO;
using ImageSharp;
using ImageSharp.Processing;
using SixLabors.Primitives;
using OpenTK.Graphics.OpenGL;
using Processing.OpenTk.Core.Extensions;
namespace Processing.OpenTk.Core.Textures
{
public class PImage
{
private readonly Image<Rgba32> _source;
public readonly uint Handle;
public readonly int Width;
public readonly int Height;
public readonly int[] Data;
private PImage(Image<Rgba32> source)
{
_source = source;
Data = GetData(source);
Width = source.Width;
Height = source.Height;
GL.GenTextures(1, out Handle);
GL.BindTexture(TextureTarget.Texture2D, Handle);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (float)TextureMagFilter.Nearest);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (float)TextureMinFilter.Nearest);
GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, Width, Height, 0, PixelFormat.Rgba, PixelType.UnsignedByte, IntPtr.Zero);
WithDataPtr(dataptr =>
{
GL.TexSubImage2D(TextureTarget.Texture2D, 0, 0, 0, Width, Height, PixelFormat.Rgba, PixelType.UnsignedByte, dataptr);
});
GL.BindTexture(TextureTarget.Texture2D, 0);
}
public static implicit operator uint (PImage image) => image.Handle;
private ResizeOptions GetResizer(int width, int height) => new ResizeOptions
{
Size = new Size(width, height),
Sampler = new BicubicResampler(),
Mode = ResizeMode.Stretch
};
public PImage Resize(int newWidth, int newHeight) => WithImageCopy(copy => GetResizer(newWidth, newHeight).Then(copy.Resize).Then(FromImage));
public PImage Rotate(float angle) => WithImageCopy(copy => copy.Rotate(angle).Then(FromImage));
public static PImage FromSteam(Func<Stream> streamSource)
{
using (var stream = streamSource())
return FromImage(Image.Load(stream));
}
public static PImage FromFile(string file) => FromImage(Image.Load(file));
public static PImage FromImage(Image<Rgba32> image) => new PImage(image);
private static int[] GetData(Image<Rgba32> image)
{
int[] data = new int[image.Pixels.Length];
int outIndex = 0;
for (int row = image.Height - 1; row >= 0; row--)
{
for (int column = 0; column < image.Width; column++)
{
int inIndex = column + (row * image.Width);
data[outIndex] = image.Pixels[inIndex].A << 24
| image.Pixels[inIndex].B << 16
| image.Pixels[inIndex].G << 8
| image.Pixels[inIndex].R;
outIndex++;
}
}
return data;
}
public void WithDataPtr(Action<IntPtr> action)
{
unsafe
{
fixed (int* dataptr = &(Data[0]))
{
action((IntPtr)dataptr);
}
}
}
private PImage WithImageCopy(Func<Image<Rgba32>, PImage> func) => func(new Image<Rgba32>(_source));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment