This repository has been archived on 2023-07-11. You can view files and clone it, but cannot push or open issues or pull requests.
Blarg.GameFramework/Blarg.GameFramework.SDL2/Graphics/SDLBitmap.cs
Gered b48a13757b add platform-independant interface for loading Image objects from streams. add SDL backend support
SDL2# does not include anything suitable for using Streams with, so we
just use System.Drawing instead for now
2013-08-18 11:54:22 -04:00

126 lines
2.9 KiB
C#

using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Runtime.InteropServices;
namespace Blarg.GameFramework.Graphics
{
public class SDLBitmap : IPlatformBitmap
{
byte[] _pixels;
int _width;
int _height;
Graphics.ImageFormat _format;
public byte[] Pixels
{
get { return _pixels; }
}
public int Width
{
get { return _width; }
}
public int Height
{
get { return _height; }
}
public Graphics.ImageFormat Format
{
get { return _format; }
}
public SDLBitmap(Stream file)
{
_pixels = GetBitmap(file, out _width, out _height, out _format);
}
private byte[] GetBitmap(Stream file, out int width, out int height, out Graphics.ImageFormat format)
{
if (file == null)
throw new ArgumentNullException("file");
using (Bitmap bitmap = (Bitmap)Bitmap.FromStream(file))
{
int bpp = 0;
if (bitmap.PixelFormat == PixelFormat.Format32bppArgb)
{
bpp = 32;
format = Graphics.ImageFormat.RGBA;
}
else if (bitmap.PixelFormat == PixelFormat.Format24bppRgb)
{
bpp = 24;
format = Graphics.ImageFormat.RGB;
}
else if (bitmap.PixelFormat == PixelFormat.Alpha)
{
bpp = 8;
format = Graphics.ImageFormat.A;
}
else
throw new InvalidOperationException(String.Format("Unsupported bitmap pixel format: {0}", bitmap.PixelFormat.ToString()));
width = bitmap.Width;
height = bitmap.Height;
byte[] pixels;
var lockRegion = new Rectangle(0, 0, bitmap.Width, bitmap.Height);
var bitmapData = bitmap.LockBits(lockRegion, ImageLockMode.ReadOnly, bitmap.PixelFormat);
try
{
int bitmapSizeInBytes = bitmap.Width * bitmap.Height * (bpp / 8);
int expectedPitch = bitmap.Width * (bpp / 8);
int actualPitch = bitmapData.Stride;
if (expectedPitch != actualPitch)
throw new InvalidOperationException("Expected bitmap pitch mismatch. Uncaught unsupported bitmap format?");
pixels = new byte[bitmapData.Stride * bitmap.Height];
Marshal.Copy(bitmapData.Scan0, pixels, 0, bitmapSizeInBytes);
}
finally
{
bitmap.UnlockBits(bitmapData);
}
// TODO: are there any cases where this should *not* be run?
SwapRgbOrdering(pixels, format);
return pixels;
}
}
private void SwapRgbOrdering(byte[] pixels, Graphics.ImageFormat pixelFormat)
{
if (pixelFormat == Graphics.ImageFormat.A)
return;
// assumption is that this will only ever be 3 or 4 (RGB, or RGBA)
int pixelSizeBytes;
if (pixelFormat == Graphics.ImageFormat.RGB)
pixelSizeBytes = 3;
else
pixelSizeBytes = 4;
if (pixels.Length % pixelSizeBytes != 0)
throw new InvalidDataException("Pixel data format mismatch.");
// swap R and B values for each pixel
for (int i = 0; i < pixels.Length; i += pixelSizeBytes)
{
byte r = pixels[i];
byte b = pixels[i + 2];
pixels[i] = b;
pixels[i + 2] = r;
}
}
}
}