241 lines
8.7 KiB
C#

using System;
using System.Collections.Generic;
namespace UniversalEditor.ObjectModels.Picture
{
public class PictureObjectModel : ObjectModel
{
private System.Drawing.Point lastAddedLocation = new System.Drawing.Point(0, 0);
private List<System.Drawing.Color> mvarColorMap = new List<System.Drawing.Color>();
public List<System.Drawing.Color> ColorMap { get { return mvarColorMap; } }
public System.Drawing.Bitmap ToBitmap()
{
byte[] imageByteArray = ToByteArray();
//************** NOTE *******************
// The memory allocated for Microsoft Bitmaps must be aligned on a 32bit boundary.
// The stride refers to the number of bytes allocated for one scanline of the bitmap.
// In your loop, you copy the pixels one scanline at a time and take into
// consideration the amount of padding that occurs due to memory alignment.
// calculate the stride, in bytes, of the image (32bit aligned width of each image row)
int pixelDepth = 32;
int stride = (((int)mvarWidth * pixelDepth + 31) & ~31) >> 3; // width in bytes
int padding = stride - ((((int)mvarWidth * pixelDepth) + 7) / 8);
byte[] newImageByteArray = new byte[imageByteArray.Length + padding];
Array.Copy(imageByteArray, 0, newImageByteArray, 0, imageByteArray.Length);
// since the Bitmap constructor requires a pointer to an array of image bytes
// we have to pin down the memory used by the byte array and use the pointer
// of this pinned memory to create the Bitmap.
// This tells the Garbage Collector to leave the memory alone and DO NOT touch it.
System.Runtime.InteropServices.GCHandle imageByteGCHandle = System.Runtime.InteropServices.GCHandle.Alloc(newImageByteArray, System.Runtime.InteropServices.GCHandleType.Pinned);
IntPtr imageByteHandle = imageByteGCHandle.AddrOfPinnedObject();
// Bitmap construction and translation to System.Drawing.Bitmap are handled
// DataFormat-agnostically by the ObjectModel. This code was adapted from the
// reference code for the TrueVisionTGADataFormat but the parameters are different...
System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap(mvarWidth, mvarHeight, stride, System.Drawing.Imaging.PixelFormat.Format32bppArgb, imageByteHandle);
/*
// get the Pixel format to use with the Bitmap object
PixelFormat pf = this.GetPixelFormat();
// load the color map into the Bitmap, if it exists
if (this.objTargaHeader.ColorMap.Count > 0)
{
// get the Bitmap's current palette
List<System.Drawing.Color> paletteEntries = new List<System.Drawing.Color>();
// loop trough each color in the loaded file's color map
for (int i = 0; i < this.objTargaHeader.ColorMap.Count; i++)
{
// is the AttributesType 0 or 1 bit
if (AttributesType == 0 || AttributesType == 1)
{
// use 255 for alpha ( 255 = opaque/visible ) so we can see the image
paletteEntries.Add(System.Drawing.Color.FromArgb(255, this.objTargaHeader.ColorMap[i].R, this.objTargaHeader.ColorMap[i].G, this.objTargaHeader.ColorMap[i].B));
}
else
{
// use whatever value is there
paletteEntries.Add(objTargaHeader.ColorMap[i]);
}
}
}
else
{
// no color map
// check to see if this is a Black and White (Greyscale)
if (mvarPixelDepth == 8 && (mvarImageType == TargaImageType.UncompressedGrayscale || mvarImageType == TargaImageType.CompressedGrayscale))
{
// get the current palette
System.Drawing.Imaging.ColorPalette pal = bitmap.Palette;
// create the grayscale palette
for (int i = 0; i < 256; i++)
{
pal.Entries[i] = System.Drawing.Color.FromArgb(i, i, i);
}
// set the new palette back to the Bitmap object
bitmap.Palette = pal;
}
}
*/
return bitmap;
}
public void SetPixel(System.Drawing.Color color)
{
if (lastAddedLocation.X >= mvarWidth && lastAddedLocation.Y >= mvarHeight)
{
throw new InvalidOperationException("Out of image space. Try resizing the image");
}
if (lastAddedLocation.X >= mvarWidth)
{
lastAddedLocation.X = 0;
lastAddedLocation.Y++;
}
SetPixel(color, lastAddedLocation.X, lastAddedLocation.Y);
}
public void SetPixel(System.Drawing.Color color, int x, int y)
{
if (x >= mvarWidth || y >= mvarHeight)
{
throw new InvalidOperationException("Out of image space. Try resizing the image");
}
int index = (x + (y * mvarWidth)) * 4;
bitmapData[index] = (byte)color.R;
bitmapData[index + 1] = (byte)color.G;
bitmapData[index + 2] = (byte)color.B;
bitmapData[index + 3] = (byte)color.A;
int realIndex = (int)(index / 4);
bitmapDataSet[realIndex] = true;
}
public void ClearPixel(int x, int y)
{
int index = (lastAddedLocation.X + (lastAddedLocation.Y * mvarWidth)) * 4;
bitmapData[index] = 0;
bitmapData[index + 1] = 0;
bitmapData[index + 2] = 0;
bitmapData[index + 3] = 0;
int realIndex = (int)(index / 4);
bitmapDataSet[realIndex] = false;
}
public System.Drawing.Color GetPixel(int x, int y)
{
if (x >= mvarWidth || y >= mvarHeight)
{
throw new InvalidOperationException("Out of image space. Try resizing the image");
}
int index = (x + (y * mvarWidth)) * 4;
int realIndex = (int)(index / 4);
if (bitmapDataSet[realIndex])
{
byte r = bitmapData[index + 0];
byte g = bitmapData[index + 1];
byte b = bitmapData[index + 2];
byte a = bitmapData[index + 3];
System.Drawing.Color color = System.Drawing.Color.FromArgb(a, r, g, b);
return color;
}
return System.Drawing.Color.Empty;
}
public System.Drawing.Color GetPixel(System.Drawing.Point point)
{
return GetPixel(point.X, point.Y);
}
private byte[] bitmapData = new byte[] { 0, 0, 0, 0 };
private bool[] bitmapDataSet = new bool[] { false };
private int mvarWidth = 1;
public int Width { get { return mvarWidth; } set { mvarWidth = value; bitmapData = new byte[mvarWidth * mvarHeight * 4]; bitmapDataSet = new bool[mvarWidth * mvarHeight]; } }
private int mvarHeight = 1;
public int Height { get { return mvarHeight; } set { mvarHeight = value; bitmapData = new byte[mvarWidth * mvarHeight * 4]; bitmapDataSet = new bool[mvarWidth * mvarHeight]; } }
public override ObjectModelReference MakeReference()
{
ObjectModelReference omr = base.MakeReference();
omr.Title = "Picture";
omr.Path = new string[] { "Multimedia", "Picture" };
return omr;
}
private PictureItem.PictureItemCollection mvarItems = new PictureItem.PictureItemCollection();
public PictureItem.PictureItemCollection Items { get { return this.mvarItems; } }
public override void Clear()
{
}
public override void CopyTo(ObjectModel destination)
{
PictureObjectModel clone = (destination as PictureObjectModel);
}
public byte[] ToByteArray()
{
// memory goes from left to right, top to bottom
byte[] data = new byte[mvarWidth * mvarHeight * 4];
int i = 0;
for (int h = 0; h < mvarHeight; h++)
{
for (int w = 0; w < mvarWidth; w++)
{
int index = (w + (h * mvarWidth)) * 4;
int realIndex = (int)(index / 4);
if (bitmapDataSet[realIndex])
{
data[i + 2] = bitmapData[index + 0];
data[i + 1] = bitmapData[index + 1];
data[i] = bitmapData[index + 2];
data[i + 3] = bitmapData[index + 3];
}
i += 4;
}
}
return data;
}
public static PictureObjectModel FromByteArray(byte[] data, int width, int height)
{
if (width == 0 || height == 0) return null;
PictureObjectModel pic = new PictureObjectModel();
pic.Width = width;
pic.Height = height;
// memory goes from left to right, top to bottom
int i = 0;
for (int h = 0; h < height; h++)
{
for (int w = 0; w < width; w++)
{
byte b = data[i];
byte g = data[i + 1];
byte r = data[i + 2];
byte a = data[i + 3];
System.Drawing.Color color = System.Drawing.Color.FromArgb(a, r, g, b);
pic.SetPixel(color, w, h);
i += 4;
}
}
return pic;
}
}
}