#region References
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
#endregion
namespace Ultima
{
public sealed class UnicodeFont
{
public UnicodeChar[] Chars { get; set; }
public UnicodeFont()
{
Chars = new UnicodeChar[0x10000];
}
///
/// Returns width of text
///
///
///
public int GetWidth(string text)
{
if (text == null || text.Length == 0)
{
return 0;
}
int width = 0;
for (int i = 0; i < text.Length; ++i)
{
int c = text[i] % 0x10000;
width += Chars[c].Width;
width += Chars[c].XOffset;
}
return width;
}
///
/// Returns max height of text
///
///
///
public int GetHeight(string text)
{
if (text == null || text.Length == 0)
{
return 0;
}
int height = 0;
for (int i = 0; i < text.Length; ++i)
{
int c = text[i] % 0x10000;
height = Math.Max(height, Chars[c].Height + Chars[c].YOffset);
}
return height;
}
}
public sealed class UnicodeChar
{
public byte[] Bytes { get; set; }
public sbyte XOffset { get; set; }
public sbyte YOffset { get; set; }
public int Height { get; set; }
public int Width { get; set; }
///
/// Gets Bitmap of Char
///
///
public Bitmap GetImage()
{
return GetImage(false);
}
///
/// Gets Bitmap of Char with Background -1
///
///
///
public unsafe Bitmap GetImage(bool fill)
{
if ((Width == 0) || (Height == 0))
{
return null;
}
var bmp = new Bitmap(Width, Height, Settings.PixelFormat);
BitmapData bd = bmp.LockBits(
new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.WriteOnly, Settings.PixelFormat);
var line = (ushort*)bd.Scan0;
int delta = bd.Stride >> 1;
for (int y = 0; y < Height; ++y, line += delta)
{
ushort* cur = line;
for (int x = 0; x < Width; ++x)
{
if (IsPixelSet(Bytes, Width, x, y))
{
cur[x] = 0x8000;
}
else if (fill)
{
cur[x] = 0xffff;
}
}
}
bmp.UnlockBits(bd);
return bmp;
}
private static bool IsPixelSet(byte[] data, int width, int x, int y)
{
int offset = x / 8 + y * ((width + 7) / 8);
if (offset > data.Length)
{
return false;
}
return (data[offset] & (1 << (7 - (x % 8)))) != 0;
}
///
/// Resets Buffer with Bitmap
///
///
public unsafe void SetBuffer(Bitmap bmp)
{
Bytes = new byte[bmp.Height * (((bmp.Width - 1) / 8) + 1)];
BitmapData bd = bmp.LockBits(
new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.WriteOnly, Settings.PixelFormat);
var line = (ushort*)bd.Scan0;
//int delta = bd.Stride >> 1;
for (int y = 0; y < bmp.Height; ++y)
{
ushort* cur = line;
for (int x = 0; x < bmp.Width; ++x)
{
if (cur[x] == 0x8000)
{
int offset = x / 8 + y * ((bmp.Width + 7) / 8);
Bytes[offset] |= (byte)(1 << (7 - (x % 8)));
}
}
}
bmp.UnlockBits(bd);
}
}
public static class UnicodeFonts
{
private static readonly string[] m_files = new[]
{
"unifont.mul", "unifont1.mul", "unifont2.mul", "unifont3.mul", "unifont4.mul", "unifont5.mul", "unifont6.mul",
"unifont7.mul", "unifont8.mul", "unifont9.mul", "unifont10.mul", "unifont11.mul", "unifont12.mul"
};
public static UnicodeFont[] Fonts = new UnicodeFont[13];
static UnicodeFonts()
{
Initialize();
}
///
/// Reads unifont*.mul
///
public static void Initialize()
{
for (int i = 0; i < m_files.Length; i++)
{
string filePath = Files.GetFilePath(m_files[i]);
if (filePath == null)
{
continue;
}
Fonts[i] = new UnicodeFont();
using (var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read))
{
using (var bin = new BinaryReader(fs))
{
for (int c = 0; c < 0x10000; ++c)
{
Fonts[i].Chars[c] = new UnicodeChar();
fs.Seek(((c) * 4), SeekOrigin.Begin);
int num2 = bin.ReadInt32();
if ((num2 >= fs.Length) || (num2 <= 0))
{
continue;
}
fs.Seek(num2, SeekOrigin.Begin);
sbyte xOffset = bin.ReadSByte();
sbyte yOffset = bin.ReadSByte();
int Width = bin.ReadByte();
int Height = bin.ReadByte();
Fonts[i].Chars[c].XOffset = xOffset;
Fonts[i].Chars[c].YOffset = yOffset;
Fonts[i].Chars[c].Width = Width;
Fonts[i].Chars[c].Height = Height;
if (!((Width == 0) || (Height == 0)))
{
Fonts[i].Chars[c].Bytes = bin.ReadBytes(Height * (((Width - 1) / 8) + 1));
}
}
}
}
}
}
///
/// Draws Text with font in Bitmap and returns
///
///
///
///
public static Bitmap WriteText(int fontId, string text)
{
var result = new Bitmap(Fonts[fontId].GetWidth(text) + 2, Fonts[fontId].GetHeight(text) + 2);
int dx = 2;
int dy = 2;
using (Graphics graph = Graphics.FromImage(result))
{
for (int i = 0; i < text.Length; ++i)
{
int c = text[i] % 0x10000;
Bitmap bmp = Fonts[fontId].Chars[c].GetImage();
dx += Fonts[fontId].Chars[c].XOffset;
graph.DrawImage(bmp, dx, dy + Fonts[fontId].Chars[c].YOffset);
dx += bmp.Width;
}
}
return result;
}
///
/// Saves Font and returns string Filename
///
///
///
///
public static string Save(string path, int filetype)
{
string FileName = Path.Combine(path, m_files[filetype]);
using (var fs = new FileStream(FileName, FileMode.Create, FileAccess.Write, FileShare.Write))
{
using (var bin = new BinaryWriter(fs))
{
fs.Seek(0x10000 * 4, SeekOrigin.Begin);
bin.Write(0);
// Set first data
for (int c = 0; c < 0x10000; ++c)
{
if (Fonts[filetype].Chars[c].Bytes == null)
{
continue;
}
fs.Seek(((c) * 4), SeekOrigin.Begin);
bin.Write((int)fs.Length);
fs.Seek(fs.Length, SeekOrigin.Begin);
bin.Write(Fonts[filetype].Chars[c].XOffset);
bin.Write(Fonts[filetype].Chars[c].YOffset);
bin.Write((byte)Fonts[filetype].Chars[c].Width);
bin.Write((byte)Fonts[filetype].Chars[c].Height);
bin.Write(Fonts[filetype].Chars[c].Bytes);
}
}
}
return FileName;
}
}
}