mirror of
https://github.com/kwsch/NHSE.git
synced 2026-03-21 17:24:30 -05:00
Added Personal for IVillagerOrigin in place of current pattern index for Load All. Moved ContainsTransparentPixels to ImageUtil.
174 lines
6.1 KiB
C#
174 lines
6.1 KiB
C#
using System;
|
|
using System.Drawing;
|
|
using System.Drawing.Drawing2D;
|
|
using System.Drawing.Imaging;
|
|
using System.Runtime.CompilerServices;
|
|
using System.Runtime.InteropServices;
|
|
using NHSE.Core;
|
|
|
|
namespace NHSE.Sprites;
|
|
|
|
public static class ImageUtil
|
|
{
|
|
extension(DesignPattern bg)
|
|
{
|
|
public Bitmap GetImage() => GetBitmap(bg.GetBitmap(), DesignPattern.Width, DesignPattern.Height);
|
|
|
|
public Bitmap GetPalette() => GetBitmap(bg.GetPaletteBitmap(), DesignPattern.PaletteColorCount, 1, PixelFormat.Format24bppRgb);
|
|
}
|
|
|
|
extension(DesignPatternPRO bg)
|
|
{
|
|
public Bitmap GetImage(int sheet) => GetBitmap(bg.GetBitmap(sheet), DesignPatternPRO.Width, DesignPatternPRO.Height);
|
|
|
|
public Bitmap GetPalette() => GetBitmap(bg.GetPaletteBitmap(), DesignPatternPRO.PaletteColorCount, 1, PixelFormat.Format24bppRgb);
|
|
}
|
|
|
|
extension(Bitmap bmp)
|
|
{
|
|
public Span<byte> GetBitmapData(out BitmapData bmpData)
|
|
{
|
|
var format = bmp.PixelFormat;
|
|
bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, format);
|
|
var bpp = Image.GetPixelFormatSize(format) / 8;
|
|
return GetSpan(bmpData.Scan0, bmp.Width * bmp.Height * bpp);
|
|
}
|
|
|
|
public void GetBitmapData(Span<byte> data)
|
|
{
|
|
var span = bmp.GetBitmapData(out var bmpData);
|
|
span.CopyTo(data);
|
|
bmp.UnlockBits(bmpData);
|
|
}
|
|
|
|
public void GetBitmapData(Span<int> data)
|
|
{
|
|
var span = bmp.GetBitmapData(out var bmpData);
|
|
var src = MemoryMarshal.Cast<byte, int>(span);
|
|
src.CopyTo(data);
|
|
bmp.UnlockBits(bmpData);
|
|
}
|
|
|
|
public void SetBitmapData(ReadOnlySpan<byte> data)
|
|
{
|
|
var span = bmp.GetBitmapData(out var bmpData);
|
|
data.CopyTo(span);
|
|
bmp.UnlockBits(bmpData);
|
|
}
|
|
|
|
public void SetBitmapData(Span<int> data)
|
|
{
|
|
var span = bmp.GetBitmapData(out var bmpData);
|
|
var dest = MemoryMarshal.Cast<byte, int>(span);
|
|
data.CopyTo(dest);
|
|
bmp.UnlockBits(bmpData);
|
|
}
|
|
}
|
|
|
|
public static bool ContainsTransparentPixels(Bitmap image)
|
|
{
|
|
for (int y = 0; y < image.Height; ++y)
|
|
{
|
|
for (int x = 0; x < image.Width; ++x)
|
|
{
|
|
if (image.GetPixel(x, y).A < 255) // check alpha
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public static Bitmap GetBitmap(ReadOnlySpan<int> data, int width, int height, PixelFormat format = PixelFormat.Format32bppArgb)
|
|
{
|
|
var span = MemoryMarshal.Cast<int, byte>(data);
|
|
return GetBitmap(span, width, height, format);
|
|
}
|
|
|
|
public static Bitmap GetBitmap(ReadOnlySpan<byte> data, int width, int height, PixelFormat format = PixelFormat.Format32bppArgb)
|
|
{
|
|
var bmp = new Bitmap(width, height, format);
|
|
var span = bmp.GetBitmapData(out var bmpData);
|
|
data[..span.Length].CopyTo(span);
|
|
bmp.UnlockBits(bmpData);
|
|
return bmp;
|
|
}
|
|
|
|
private static Span<byte> GetSpan(IntPtr ptr, int length)
|
|
=> MemoryMarshal.CreateSpan(ref Unsafe.AddByteOffset(ref Unsafe.NullRef<byte>(), ptr), length);
|
|
|
|
// https://stackoverflow.com/a/24199315
|
|
public static Bitmap ResizeImage(Image image, int width, int height)
|
|
{
|
|
var destRect = new Rectangle(0, 0, width, height);
|
|
var destImage = new Bitmap(width, height);
|
|
|
|
destImage.SetResolution(image.HorizontalResolution, image.VerticalResolution);
|
|
|
|
using var wrapMode = new ImageAttributes();
|
|
wrapMode.SetWrapMode(WrapMode.TileFlipXY);
|
|
|
|
using var graphics = Graphics.FromImage(destImage);
|
|
graphics.CompositingMode = CompositingMode.SourceCopy;
|
|
graphics.CompositingQuality = CompositingQuality.HighQuality;
|
|
graphics.InterpolationMode = InterpolationMode.NearestNeighbor;
|
|
graphics.SmoothingMode = SmoothingMode.HighQuality;
|
|
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
|
|
|
|
graphics.DrawImage(image, destRect, 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, wrapMode);
|
|
|
|
return destImage;
|
|
}
|
|
|
|
public static int[] ScalePixelImage(ReadOnlySpan<int> data, int imgScale, int imgWidthSingle, int imgHeightSingle, out int imgWidthUpscaled, out int imgHeightUpscaled)
|
|
{
|
|
imgWidthUpscaled = imgScale * imgWidthSingle;
|
|
imgHeightUpscaled = imgScale * imgHeightSingle;
|
|
var scaled = new int[imgWidthUpscaled * imgHeightUpscaled];
|
|
ScalePixelImage(data, scaled, imgWidthUpscaled, imgHeightUpscaled, imgScale);
|
|
return scaled;
|
|
}
|
|
|
|
public static void ScalePixelImage(ReadOnlySpan<int> data, Span<int> scaled, int imgWidth, int imgHeight, int imgScale)
|
|
{
|
|
// For each pixel, copy to the X indexes, then block copy the row to the other rows.
|
|
int i = 0;
|
|
for (int y = 0; y < imgHeight; y += imgScale)
|
|
{
|
|
// Fill the X pixels
|
|
var baseIndex = y * imgWidth;
|
|
for (int x = 0; x < imgWidth; x += imgScale)
|
|
{
|
|
var v = data[i];
|
|
var xi = baseIndex + x;
|
|
for (int x1 = 0; x1 < imgScale; x1++)
|
|
scaled[xi + x1] = v;
|
|
i++;
|
|
}
|
|
|
|
// Copy entire pixel row down
|
|
for (int y1 = 1; y1 < imgScale; y1++)
|
|
{
|
|
var src = scaled.Slice(baseIndex, imgWidth);
|
|
var dest = scaled.Slice(baseIndex + (y1 * imgWidth), imgWidth);
|
|
src.CopyTo(dest);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets a bitwise and of the requested transparency; this is assuming the pixel value is 0xFF_xx_xx_xx. Single operation laziness!
|
|
/// </summary>
|
|
public static void ClampAllTransparencyTo(Span<int> data, int trans)
|
|
{
|
|
for (int i = 0; i < data.Length; i++)
|
|
data[i] &= trans;
|
|
}
|
|
|
|
public static void ClampAllTransparencyTo(Span<byte> data, byte trans)
|
|
{
|
|
for (int i = 0; i < data.Length; i += 4)
|
|
data[i + 3] &= trans;
|
|
}
|
|
} |