mirror of
https://github.com/spiffcode/hostile-takeover.git
synced 2026-02-17 10:33:03 -07:00
611 lines
18 KiB
C#
611 lines
18 KiB
C#
using System;
|
|
using System.Collections;
|
|
using System.Drawing;
|
|
using System.Drawing.Drawing2D;
|
|
using System.Drawing.Imaging;
|
|
using System.IO;
|
|
using System.Runtime.Serialization;
|
|
|
|
namespace SpiffCode
|
|
{
|
|
/// <summary>
|
|
/// Summary description for XBitmap.
|
|
/// </summary>
|
|
|
|
// UNDONE: implement IDisposable and m_bm.Dispose()
|
|
|
|
[Serializable]
|
|
public class XBitmap : ISerializable {
|
|
private Bitmap m_bm;
|
|
private Bitmap m_bmBlack;
|
|
private string m_strFileName;
|
|
private bool m_fDirty = false;
|
|
|
|
public XBitmap(string strFileName) {
|
|
Load(strFileName, false);
|
|
}
|
|
|
|
public XBitmap(string strFileName, bool fFrame) {
|
|
Load(strFileName, true);
|
|
}
|
|
|
|
private XBitmap(Bitmap bm, Bitmap bmBlack, string strFileName,
|
|
bool fDirty) {
|
|
m_bm = bm;
|
|
m_bmBlack = bmBlack;
|
|
m_strFileName = strFileName;
|
|
m_fDirty = fDirty;
|
|
}
|
|
|
|
public XBitmap Clone() {
|
|
return new XBitmap((Bitmap)m_bm.Clone(),
|
|
m_bmBlack == null ? null : (Bitmap)m_bmBlack.Clone(),
|
|
(string)m_strFileName.Clone(), m_fDirty);
|
|
}
|
|
|
|
public static string[] FilterFileNames(string[] astrFileNames) {
|
|
ArrayList alFilenames = new ArrayList();
|
|
foreach (string strFile in astrFileNames) {
|
|
try {
|
|
HasBlackCompanion(strFile);
|
|
alFilenames.Add(strFile);
|
|
} catch (Exception) {
|
|
}
|
|
}
|
|
return (string[])alFilenames.ToArray(typeof(string));
|
|
}
|
|
|
|
// Public properties
|
|
|
|
public Bitmap Bitmap {
|
|
get {
|
|
return m_bm;
|
|
}
|
|
set {
|
|
if (m_bmBlack != null) {
|
|
throw new Exception("Setting bitmap on XBitmap with black counterpart!");
|
|
}
|
|
m_bm = value;
|
|
m_fDirty = true;
|
|
}
|
|
}
|
|
|
|
public string FileName {
|
|
get {
|
|
return m_strFileName;
|
|
}
|
|
set {
|
|
m_strFileName = value;
|
|
}
|
|
}
|
|
|
|
public int Width {
|
|
get {
|
|
return m_bm.Width;
|
|
}
|
|
}
|
|
|
|
public int Height {
|
|
get {
|
|
return m_bm.Height;
|
|
}
|
|
}
|
|
|
|
public bool Dirty {
|
|
get {
|
|
return m_fDirty;
|
|
}
|
|
set {
|
|
m_fDirty = value;
|
|
}
|
|
}
|
|
|
|
private static bool HasBlackCompanion(string strFile) {
|
|
// 32 bit XBitmaps have a companion black_<filename>, which
|
|
// is used for side color extraction. 8 bit XBitmaps
|
|
// do not have this. Encapsulate this knowledge here in XBitmap.
|
|
|
|
string strPath = Path.GetDirectoryName(strFile);
|
|
string strFileName = Path.GetFileName(strFile);
|
|
|
|
// Ensure the filename doesn't start with black_, otherwise raise
|
|
// an exception.
|
|
|
|
if (strFile.StartsWith("black_")) {
|
|
throw new Exception("image file with black_: " + strFile);
|
|
}
|
|
|
|
// File is ok; see if there is a black_ counterpart. If there is,
|
|
// this bitmap file is meant to be 32 bit
|
|
if (File.Exists(Path.Combine(strPath, "black_" + strFileName))) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//
|
|
|
|
private void Load(string strFile, bool fUseFirstPaletteEntryAsTransparentColor) {
|
|
if (HasBlackCompanion(strFile)) {
|
|
Load32(strFile);
|
|
} else {
|
|
Load8(strFile, fUseFirstPaletteEntryAsTransparentColor);
|
|
}
|
|
}
|
|
|
|
private void Load32(string strFile) {
|
|
if (!HasBlackCompanion(strFile)) {
|
|
throw new Exception("doesn't have black_ counterpart: " +
|
|
strFile);
|
|
}
|
|
m_strFileName = strFile;
|
|
m_bm = new Bitmap(strFile);
|
|
string strPath = Path.GetDirectoryName(strFile);
|
|
string strFileName = Path.GetFileName(strFile);
|
|
m_bmBlack = new Bitmap(Path.Combine(strPath, "black_" + strFileName));
|
|
}
|
|
|
|
private void Load8(string strFileName, bool fUseFirstPaletteEntryAsTransparentColor) {
|
|
m_strFileName = strFileName;
|
|
m_bm = new Bitmap(strFileName);
|
|
m_bmBlack = null;
|
|
|
|
// All pixels the same color as the upper-left pixel get mapped to the
|
|
// transparent color
|
|
|
|
Color clrTransparent = Color.FromArgb(0xff, 0, 0xff);
|
|
SolidBrush brTransparent = new SolidBrush(clrTransparent);
|
|
|
|
m_bm.MakeTransparent(fUseFirstPaletteEntryAsTransparentColor ? m_bm.Palette.Entries[0] : m_bm.GetPixel(0, 0));
|
|
|
|
Bitmap bmT = new Bitmap(m_bm.Width, m_bm.Height, PixelFormat.Format24bppRgb);
|
|
using (Graphics g = Graphics.FromImage(bmT)) {
|
|
|
|
// Prep the new image by filling with the transparent color
|
|
|
|
g.FillRectangle(brTransparent, 0, 0, m_bm.Width, m_bm.Height);
|
|
|
|
// Convert the Bitmap to 24-bpp while leaving transparent pixels behind
|
|
|
|
g.DrawImageUnscaled(m_bm, 0, 0);
|
|
m_bm.Dispose();
|
|
}
|
|
|
|
m_bm = bmT;
|
|
// m_bm.MakeTransparent(clrTransparent);
|
|
}
|
|
|
|
public void Save(string strFileName) {
|
|
if (strFileName == null) {
|
|
strFileName = m_strFileName;
|
|
}
|
|
m_bm.Save(strFileName);
|
|
|
|
if (m_bmBlack != null) {
|
|
string strPath = Path.GetDirectoryName(strFileName);
|
|
string strFileT = Path.GetFileName(strFileName);
|
|
m_bmBlack.Save(Path.Combine(strPath, "black_" + strFileT));
|
|
}
|
|
|
|
m_fDirty = false;
|
|
}
|
|
|
|
/*
|
|
* given h,s,l on [0..1],
|
|
* return r,g,b on [0..1]
|
|
* From Graphics Gems
|
|
*/
|
|
unsafe static void Hsl2Rgb(double h, double sl, double l,
|
|
double *r, double *g, double *b) {
|
|
double v;
|
|
|
|
v = (l <= 0.5) ? (l * (1.0 + sl)) : (l + sl - l * sl);
|
|
if (v <= 0) {
|
|
*r = *g = *b = 0.0;
|
|
} else {
|
|
double m;
|
|
double sv;
|
|
int sextant;
|
|
double fract, vsf, mid1, mid2;
|
|
|
|
m = l + l - v;
|
|
sv = (v - m ) / v;
|
|
h *= 6.0;
|
|
sextant = (int)h;
|
|
fract = h - sextant;
|
|
vsf = v * sv * fract;
|
|
mid1 = m + vsf;
|
|
mid2 = v - vsf;
|
|
switch (sextant) {
|
|
case 0: *r = v; *g = mid1; *b = m; break;
|
|
case 1: *r = mid2; *g = v; *b = m; break;
|
|
case 2: *r = m; *g = v; *b = mid1; break;
|
|
case 3: *r = m; *g = mid2; *b = v; break;
|
|
case 4: *r = mid1; *g = m; *b = v; break;
|
|
case 5: *r = v; *g = m; *b = mid2; break;
|
|
}
|
|
}
|
|
}
|
|
|
|
unsafe static void Hsl2Rgb360(double h, double s, double l,
|
|
RgbData *prgb) {
|
|
// Convert 0..360 to 0..1
|
|
double r, g, b;
|
|
Hsl2Rgb(h / 360.0, s, l, &r, &g, &b);
|
|
prgb->bRed = (byte)(r * 255.0);
|
|
prgb->bGreen = (byte)(g * 255.0);
|
|
prgb->bBlue = (byte)(b * 255.0);
|
|
}
|
|
|
|
struct RgbaData {
|
|
public RgbaData(byte bAlpha, byte bRed, byte bGreen, byte bBlue) {
|
|
this.bAlpha = bAlpha;
|
|
this.bRed = bRed;
|
|
this.bGreen = bGreen;
|
|
this.bBlue = bBlue;
|
|
}
|
|
|
|
public byte bBlue;
|
|
public byte bGreen;
|
|
public byte bRed;
|
|
public byte bAlpha;
|
|
}
|
|
|
|
struct RgbData {
|
|
public RgbData(byte bRed, byte bGreen, byte bBlue) {
|
|
this.bRed = bRed;
|
|
this.bGreen = bGreen;
|
|
this.bBlue = bBlue;
|
|
}
|
|
|
|
public byte bBlue;
|
|
public byte bGreen;
|
|
public byte bRed;
|
|
}
|
|
|
|
static RgbData[] argbSide = {
|
|
new RgbData(232, 32, 0),
|
|
new RgbData(196, 28, 0),
|
|
new RgbData(128, 8, 0),
|
|
new RgbData(92, 8, 0),
|
|
new RgbData(64, 8, 0),
|
|
};
|
|
|
|
public unsafe void SuperBlt(int xSrc, int ySrc,
|
|
BitmapData bmdDst, int xDst, int yDst, int cx, int cy,
|
|
bool fMapSideColors) {
|
|
if (m_bmBlack == null) {
|
|
SuperBlt8(xSrc, ySrc, bmdDst, xDst, yDst, cx, cy,
|
|
fMapSideColors);
|
|
} else {
|
|
SuperBlt32(xSrc, ySrc, bmdDst, xDst, yDst, cx, cy,
|
|
fMapSideColors);
|
|
}
|
|
}
|
|
|
|
public unsafe void SuperBlt32(int xSrc, int ySrc,
|
|
BitmapData bmdDst, int xDst, int yDst, int cx, int cy,
|
|
bool fMapSideColors) {
|
|
|
|
// If completely off dst bounds, just return.
|
|
|
|
if ((xDst >= bmdDst.Width || xDst + cx < 0) ||
|
|
(yDst >= bmdDst.Height) || (yDst + cy < 0)) {
|
|
return;
|
|
}
|
|
|
|
// Dst clip
|
|
|
|
if (xDst + cx > bmdDst.Width)
|
|
cx = bmdDst.Width - xDst;
|
|
if (yDst + cy > bmdDst.Height)
|
|
cy = bmdDst.Height - yDst;
|
|
|
|
if (xDst < 0) {
|
|
cx += xDst;
|
|
xSrc -= xDst;
|
|
xDst = 0;
|
|
}
|
|
|
|
if (yDst < 0) {
|
|
cy += yDst;
|
|
ySrc -= yDst;
|
|
yDst = 0;
|
|
}
|
|
|
|
BitmapData bmdSrc = m_bm.LockBits(
|
|
new Rectangle(0, 0, m_bm.Width, m_bm.Height),
|
|
ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
|
|
BitmapData bmdSrcBlack = m_bmBlack.LockBits(
|
|
new Rectangle(0, 0, m_bmBlack.Width, m_bmBlack.Height),
|
|
ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
|
|
|
|
RgbaData* prgbSrc = (RgbaData*)((byte*)bmdSrc.Scan0 +
|
|
(ySrc * bmdSrc.Stride) + (xSrc * sizeof(RgbaData)));
|
|
RgbaData* prgbSrcBlack = (RgbaData*)((byte*)bmdSrcBlack.Scan0 +
|
|
(ySrc * bmdSrcBlack.Stride) + (xSrc * sizeof(RgbaData)));
|
|
RgbData* prgbDst = (RgbData*)((byte*)bmdDst.Scan0 +
|
|
(yDst * bmdDst.Stride) + (xDst * sizeof(RgbData)));
|
|
|
|
while (cy-- > 0) {
|
|
RgbaData* prgbSrcT = prgbSrc;
|
|
RgbaData* prgbSrcBlackT = prgbSrcBlack;
|
|
RgbData* prgbDstT = prgbDst;
|
|
|
|
for (int x = 0; x < cx; x++) {
|
|
RgbaData rgbSrc = *prgbSrcT++;
|
|
RgbaData rgbSrcBlack = *prgbSrcBlackT++;
|
|
|
|
// rgbSrc = huemap(rgbSrc - rgbSrcBlack) + rgbSrcBlack
|
|
|
|
RgbData rgbT;
|
|
int v;
|
|
v = rgbSrc.bRed - rgbSrcBlack.bRed;
|
|
if (v < 0) {
|
|
v = 0;
|
|
}
|
|
rgbT.bRed = (byte)v;
|
|
|
|
v = rgbSrc.bGreen - rgbSrcBlack.bGreen;
|
|
if (v < 0) {
|
|
v = 0;
|
|
}
|
|
rgbT.bGreen = (byte)v;
|
|
|
|
v = rgbSrc.bBlue - rgbSrcBlack.bBlue;
|
|
if (v < 0) {
|
|
v = 0;
|
|
}
|
|
rgbT.bBlue = (byte)v;
|
|
|
|
Color clrT = Color.FromArgb(rgbT.bRed, rgbT.bGreen,
|
|
rgbT.bBlue);
|
|
double hue = clrT.GetHue();
|
|
if (fMapSideColors) {
|
|
hue -= 235.0;
|
|
if (hue < 0.0) {
|
|
hue += 360.0;
|
|
}
|
|
}
|
|
Hsl2Rgb360(hue, clrT.GetSaturation(), clrT.GetBrightness(),
|
|
&rgbT);
|
|
|
|
// Add new rgb back to black
|
|
v = rgbSrcBlack.bRed + rgbT.bRed;
|
|
if (v > 255) {
|
|
v = 255;
|
|
}
|
|
rgbSrc.bRed = (byte)v;
|
|
|
|
v = rgbSrcBlack.bGreen + rgbT.bGreen;
|
|
if (v > 255) {
|
|
v = 255;
|
|
}
|
|
rgbSrc.bGreen = (byte)v;
|
|
|
|
v = rgbSrcBlack.bBlue + rgbT.bBlue;
|
|
if (v > 255) {
|
|
v = 255;
|
|
}
|
|
rgbSrc.bBlue = (byte)v;
|
|
|
|
// Alpha blend into dest
|
|
double alpha = (double)rgbSrc.bAlpha / 255.0;
|
|
double d;
|
|
d = (double)rgbSrc.bRed * alpha +
|
|
(double)prgbDstT->bRed * (1.0 - alpha);
|
|
if (d > 255.0) {
|
|
d = 255.0;
|
|
}
|
|
prgbDstT->bRed = (byte)d;
|
|
|
|
d = (double)rgbSrc.bGreen * alpha +
|
|
(double)prgbDstT->bGreen * (1.0 - alpha);
|
|
if (d > 255.0) {
|
|
d = 255.0;
|
|
}
|
|
prgbDstT->bGreen = (byte)d;
|
|
|
|
d = (double)rgbSrc.bBlue * alpha +
|
|
(double)prgbDstT->bBlue * (1.0 - alpha);
|
|
if (d > 255.0) {
|
|
d = 255.0;
|
|
}
|
|
prgbDstT->bBlue = (byte)d;
|
|
prgbDstT++;
|
|
}
|
|
|
|
// Advance to next scan line
|
|
|
|
prgbDst = (RgbData*)(((byte*)prgbDst) + bmdDst.Stride);
|
|
prgbSrc = (RgbaData*)(((byte*)prgbSrc) + bmdSrc.Stride);
|
|
prgbSrcBlack = (RgbaData*)(((byte*)prgbSrcBlack) +
|
|
bmdSrcBlack.Stride);
|
|
}
|
|
|
|
m_bm.UnlockBits(bmdSrc);
|
|
m_bmBlack.UnlockBits(bmdSrcBlack);
|
|
}
|
|
|
|
// Skips dst where src has transparent color.
|
|
// Darkens dst where src has shadow color.
|
|
// Translates side colors.
|
|
// NOTE: Performs dst but not src clipping!!!
|
|
// NOTE: Assumes src and dst BitmapData are PixelFormat.Format24bppRgb
|
|
|
|
public unsafe void SuperBlt8(int xSrc, int ySrc,
|
|
BitmapData bmdDst, int xDst, int yDst, int cx, int cy,
|
|
bool fMapSideColors) {
|
|
|
|
// If completely off dst bounds, just return.
|
|
|
|
if ((xDst >= bmdDst.Width || xDst + cx < 0) || (yDst >= bmdDst.Height) || (yDst + cy < 0))
|
|
return;
|
|
|
|
// Dst clip
|
|
|
|
if (xDst + cx > bmdDst.Width)
|
|
cx = bmdDst.Width - xDst;
|
|
if (yDst + cy > bmdDst.Height)
|
|
cy = bmdDst.Height - yDst;
|
|
|
|
if (xDst < 0) {
|
|
cx += xDst;
|
|
xSrc -= xDst;
|
|
xDst = 0;
|
|
}
|
|
|
|
if (yDst < 0) {
|
|
cy += yDst;
|
|
ySrc -= yDst;
|
|
yDst = 0;
|
|
}
|
|
|
|
BitmapData bmdSrc = m_bm.LockBits(
|
|
new Rectangle(0, 0, m_bm.Width, m_bm.Height),
|
|
ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
|
|
|
|
RgbData* prgbSrc = (RgbData*)((byte*)bmdSrc.Scan0 + (ySrc * bmdSrc.Stride) + (xSrc * sizeof(RgbData)));
|
|
RgbData* prgbDst = (RgbData*)((byte*)bmdDst.Scan0 + (yDst * bmdDst.Stride) + (xDst * sizeof(RgbData)));
|
|
|
|
while (cy-- > 0) {
|
|
RgbData* prgbDstT = prgbDst;
|
|
RgbData* prgbSrcT = prgbSrc;
|
|
|
|
for (int x = 0; x < cx; x++) {
|
|
RgbData rgbSrc = *prgbSrcT++;
|
|
|
|
// Handle shadow color
|
|
|
|
if (rgbSrc.bRed == 156 && rgbSrc.bGreen == 212 & rgbSrc.bBlue == 248) {
|
|
prgbDstT->bRed = (byte)((prgbDstT->bRed * 60) / 100);
|
|
prgbDstT->bGreen = (byte)((prgbDstT->bGreen * 60) / 100);
|
|
prgbDstT->bBlue = (byte)((prgbDstT->bBlue * 60) / 100);
|
|
prgbDstT++;
|
|
|
|
// Handle transparent color
|
|
|
|
} else if (rgbSrc.bRed == 255 && rgbSrc.bGreen == 0 && rgbSrc.bBlue == 255) {
|
|
prgbDstT++;
|
|
|
|
// Handle side colors
|
|
|
|
} else if (fMapSideColors) {
|
|
if (rgbSrc.bRed == 0 && rgbSrc.bGreen == 116 && rgbSrc.bBlue == 232) {
|
|
*prgbDstT++ = argbSide[0];
|
|
} else if (rgbSrc.bRed == 0 && rgbSrc.bGreen == 96 && rgbSrc.bBlue == 196) {
|
|
*prgbDstT++ = argbSide[1];
|
|
} else if (rgbSrc.bRed == 0 && rgbSrc.bGreen == 64 && rgbSrc.bBlue == 120) {
|
|
*prgbDstT++ = argbSide[2];
|
|
} else if (rgbSrc.bRed == 0 && rgbSrc.bGreen == 48 && rgbSrc.bBlue == 92) {
|
|
*prgbDstT++ = argbSide[3];
|
|
} else if (rgbSrc.bRed == 0 && rgbSrc.bGreen == 32 && rgbSrc.bBlue == 64) {
|
|
*prgbDstT++ = argbSide[4];
|
|
} else {
|
|
*prgbDstT++ = rgbSrc;
|
|
}
|
|
|
|
// Just copy everything else unaltered
|
|
|
|
} else {
|
|
*prgbDstT++ = rgbSrc;
|
|
}
|
|
}
|
|
|
|
// Advance to next scan line
|
|
|
|
prgbDst = (RgbData*)(((byte*)prgbDst) + bmdDst.Stride);
|
|
prgbSrc = (RgbData*)(((byte*)prgbSrc) + bmdSrc.Stride);
|
|
}
|
|
|
|
m_bm.UnlockBits(bmdSrc);
|
|
}
|
|
|
|
public static Rectangle CalcRealBounds(Bitmap bm) {
|
|
Color clrTransparent = Color.FromArgb(0xff, 0, 0xff);
|
|
SolidBrush brTransparent = new SolidBrush(clrTransparent);
|
|
|
|
// OPT: this could be made faster by doing four independent edge scans
|
|
|
|
int xL = bm.Width;
|
|
int xR = 0;
|
|
int yT = bm.Height;
|
|
int yB = 0;
|
|
for (int y = 0; y < bm.Height; y++) {
|
|
for (int x = 0; x < bm.Width; x++) {
|
|
Color clr = bm.GetPixel(x, y);
|
|
if (clr != clrTransparent) {
|
|
xL = Math.Min(xL, x);
|
|
xR = Math.Max(xR, x);
|
|
yT = Math.Min(yT, y);
|
|
yB = Math.Max(yB, y);
|
|
}
|
|
}
|
|
}
|
|
int cx = xR - xL + 1;
|
|
int cy = yB - yT + 1;
|
|
|
|
#if false
|
|
Bitmap bmT = new Bitmap(cx, cy, PixelFormat.Format24bppRgb);
|
|
using (Graphics g = Graphics.FromImage(bmT)) {
|
|
Rectangle rcT = new Rectangle(xL, yT, cx, cy);
|
|
g.DrawImage(bm, 0, 0, rcT, GraphicsUnit.Pixel);
|
|
}
|
|
#endif
|
|
return new Rectangle(xL, yT, cx, cy);
|
|
}
|
|
|
|
public Bitmap MakeThumbnail(int cxThumb, int cyThumb, bool fFilter) {
|
|
Rectangle rcSrc = XBitmap.CalcRealBounds(m_bm);
|
|
if (rcSrc.Width <= 0 || rcSrc.Height <= 0)
|
|
return m_bm;
|
|
|
|
int cxy = Math.Max(rcSrc.Width, rcSrc.Height);
|
|
Bitmap bmDst = new Bitmap(cxy, cxy);
|
|
Graphics gDst = Graphics.FromImage(bmDst);
|
|
gDst.Clear(Color.White);
|
|
gDst.Dispose();
|
|
int xDst = (bmDst.Width - rcSrc.Width) / 2;
|
|
int yDst = (bmDst.Height - rcSrc.Height) / 2;
|
|
|
|
BitmapData bmdDst = bmDst.LockBits(
|
|
new Rectangle(0, 0, bmDst.Width, bmDst.Height),
|
|
ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
|
|
|
|
SuperBlt(rcSrc.X, rcSrc.Y, bmdDst, xDst, yDst,
|
|
rcSrc.Width, rcSrc.Height, false);
|
|
|
|
bmDst.UnlockBits(bmdDst);
|
|
|
|
Bitmap bmLarge = new Bitmap(cxThumb, cyThumb);
|
|
Graphics g = Graphics.FromImage(bmLarge);
|
|
InterpolationMode imOld = g.InterpolationMode;
|
|
g.InterpolationMode = fFilter ? InterpolationMode.Bicubic : InterpolationMode.NearestNeighbor;
|
|
PixelOffsetMode pomOld = g.PixelOffsetMode;
|
|
g.PixelOffsetMode = PixelOffsetMode.Half;
|
|
|
|
g.DrawImage(bmDst, 0, 0, cxThumb, cyThumb);
|
|
|
|
g.PixelOffsetMode = pomOld;
|
|
g.InterpolationMode = imOld;
|
|
|
|
g.Dispose();
|
|
bmDst.Dispose();
|
|
|
|
return bmLarge;
|
|
}
|
|
|
|
// ISerializable interface implementation
|
|
|
|
private XBitmap(SerializationInfo seri, StreamingContext stmc) {
|
|
string strFileName = seri.GetString("FileName");
|
|
strFileName = strFileName.Replace(@"\", Path.DirectorySeparatorChar.ToString());
|
|
Load(strFileName, false);
|
|
}
|
|
|
|
void ISerializable.GetObjectData(SerializationInfo seri, StreamingContext stmc) {
|
|
seri.AddValue("FileName", m_strFileName);
|
|
}
|
|
}
|
|
}
|