使い方
var image = reader.CreateBitmap(@"c:\temp\test.sld","");
var image2 = reader.CreateBitmap(@"c:\temp\test.slb","BOX");
var reader = new SlideImageReader();
コード
/*** SlideImageReader.cs* (c) 2019 CAD Khan <cadkhan2019@gmail.com>* License: MIT*/using System;using System.IO;using System.Collections.Generic;using System.Drawing;using System.Text;namespace SlideViewer{public class SlideImageReader{/// <summary>/// スライドのペン幅/// </summary>public float width { get; set; }/// <summary>/// コンストラクタ/// </summary>public SlideImageReader(){width = 0F;}/// <summary>/// スライドライブラリ(バイト列)からスライド名のリストを取得/// </summary>/// <param name="bs"></param>/// <returns></returns>public List<string> slideList(byte[] bs){List<string> list = new List<string>();// スライド ライブラリからスライド データを取得するif (bs.Length > 32){// 正しいスライドライブラリかどうか// ヘッダー部分(32バイト) シグネチャ+CR+LF+EOF 残り 00 で埋めているif (string.Compare(Encoding.ASCII.GetString(bs, 0, 25), "AutoCAD Slide Library 1.0") == 0){for (int i = 0; ; i++){string testname = Encoding.ASCII.GetString(bs, 32 + i * 36, 32);testname = testname.Trim('\x00');if (testname.Length == 0){break;}list.Add(testname);}}}return list;}/// <summary>/// スライドライブラリファイル(SLB)からスライド名のリストを取得/// </summary>/// <param name="filename"></param>/// <returns></returns>public List<string> slideList(string filename){byte[] bs = new byte[] { };try{bs = File.ReadAllBytes(filename);}catch (Exception){}return slideList(bs);}/// <summary>/// スライドまたはスライドライブラリ(リソース)から指定したスライドのビットマップを取得/// </summary>/// <param name="resdata">リソースデータ</param>/// <param name="slidename">スライド名</param>/// <returns></returns>public Bitmap CreateBitmap(byte[] resdata, string slidename){byte[] bs = resdata.Clone() as byte[];return _CreateBitmap(bs, slidename);}/// <summary>/// スライドまたはスライドライブラリ(ファイル)から指定したスライドのビットマップを取得/// </summary>/// <param name="filename">ファイル名</param>/// <param name="slidename">スライド名</param>/// <returns></returns>public Bitmap CreateBitmap(string filename, string slidename){// スライド ファイルかスライド ライブラリ ファイルを読み込むbyte[] bs = new byte[] { };try{bs = File.ReadAllBytes(filename);}catch (Exception){;}return _CreateBitmap(bs, slidename);}// 1バイトの符号付き整数の足し算private int Add(int b, byte d) => d < 128 ? b + d : b - 256 + d;/// <summary>/// スライドまたはスライドライブラリ(バイト列)から指定したスライドのビットマップを取得/// </summary>/// <remarks>/// バイト列がスライドのときスライド名は無視する/// </remarks>/// <param name="bs">バイト列</param>/// <param name="slidename">スライド名</param>/// <returns>ビットマップ</returns>private Bitmap _CreateBitmap(byte[] bs, string slidename){// 作図環境(Graphics)を仮のビットマップで作成するBitmap retBitmap = new Bitmap(1, 1);Graphics retBitmapGraphics = Graphics.FromImage(retBitmap);if (bs.Length > 25){// スライド ライブラリからスライド データを取得する// 正しいスライドライブラリかどうか// ヘッダー部分(32バイト) シグネチャ+CR+LF+EOF 残り 00 で埋めているif (string.Compare(Encoding.ASCII.GetString(bs, 0, 25), "AutoCAD Slide Library 1.0") == 0){for (int i = 0; ; i++){// インデックス部分(36バイト)// スライド名(32バイト) スライド名が短いときは 00 で埋めている// オフセット(4バイト) INT32// インデックス部分の最後は 36バイト 00 で埋めているstring testname = Encoding.ASCII.GetString(bs, 32 + i * 36, 32);testname = testname.Trim('\x00');// インデックス部分の最後を検出したときif (testname.Length == 0){goto NoSlide;}// スライド名が一致したときif (String.Compare(testname, slidename, true) == 0){// このスライドの開始位置を取得int offset = BitConverter.ToInt32(bs, 32 + i * 36 + 32);// 次のスライドの開始位置を取得int next = BitConverter.ToInt32(bs, 32 + (i + 1) * 36 + 32);// インデックスの最後の場合はファイルサイズを使用if (next == 0){next = bs.Length;}// スライド データをバイト配列の先頭にコピーするBuffer.BlockCopy(bs, offset, bs, 0, next - offset);// バイト配列を切り詰めるArray.Resize<byte>(ref bs, next - offset);break;}}}}// スライドデータをチェックするif (bs.Length > 32){// ヘッダー部分のフォーマット// 0: シグネチャ+CR+LF+EOF+NUL// 17: 56 (1B) ファイル種類// 18: 02 (1B) バージョン// 19: 幅 (2B) ピクセル単位スライドの幅(LSB)// 21: 高さ (2B) ピクセル単位スライドの高さ(LSB)// 23: 縦横比(4B) 10,000,000 で割った値がスライドの縦横比// 27: マシン(2B) 0か2 (LSB)// 29: バイト(2B) $1234 データ部の座標値がLSBかMSBか// このプログラムでは LSB 前提にしているstring text = Encoding.ASCII.GetString(bs, 0, 13);if (string.Compare(text, "AutoCAD Slide") == 0){// ビットマップをリサイズvar bitmapWidth = BitConverter.ToInt16(bs, 19);var bitmapHeight = BitConverter.ToInt16(bs, 21);retBitmap = new Bitmap(bitmapWidth, bitmapHeight);retBitmapGraphics = Graphics.FromImage(retBitmap);// データ部の読み取り// 座標は左下が(0,0)でピクセル単位である// 31バイトからint lastX = 0;int lastY = 0;int fromX = 0;int fromY = 0;int toX = 0;int toY = 0;int num = 0;List<Point> ps = new List<Point>();Pen pen = new Pen(Color.White, width);for (int index = 31; index < bs.Length;){// 二モニックの確認switch (bs[index + 1]){case 0xFF: // 色コードpen.Color = fromColorIndex((ushort)bs[index]);index += 2;break;case 0xFE: // 短ベクトルtoX = Add(lastX, bs[index]);toY = Add(lastY, bs[index + 2]);retBitmapGraphics.DrawLine(pen, lastX, lastY, toX, toY);lastX = toX;lastY = toY;index += 3;break;case 0xFD: // 塗り潰しtoX = BitConverter.ToInt16(bs, index + 2);toY = BitConverter.ToInt16(bs, index + 4);index += 6;// 最初のレコードのXは頂点数if (num == 0){num = toX;}else{// 最後のレコードのYは負の数--num;if (toY < 0){toY = -toY;num = 0;}Point last = new Point(toX, toY);// 頂点を保存するif (ps.Count == 0 || last != ps[ps.Count - 1]){ps.Add(last);}// 最後のレコードで描画するif (num == 0){if (ps.Count >= 3){retBitmapGraphics.FillPolygon(pen.Brush, ps.ToArray());}ps.Clear();}}//System.Diagnostics.Debug.WriteLine("{0}:{1},{2}", num, toX, toY);break;case 0xFC: // 終了index = bs.Length + 1;break;case 0xFB: // ベクトルfromX = Add(lastX, bs[index]);fromY = Add(lastY, bs[index + 2]);toX = Add(lastX, bs[index + 3]);toY = Add(lastY, bs[index + 4]);retBitmapGraphics.DrawLine(pen, fromX, fromY, toX, toY);lastX = fromX;lastY = fromY;index += 5;break;default: // 始点・終点fromX = BitConverter.ToInt16(bs, index);fromY = BitConverter.ToInt16(bs, index + 2);toX = BitConverter.ToInt16(bs, index + 4);toY = BitConverter.ToInt16(bs, index + 6);retBitmapGraphics.DrawLine(pen, fromX, fromY, toX, toY);lastX = fromX;lastY = fromY;index += 8;break;}}}}NoSlide:// 作図を行いビットマップに反映するretBitmapGraphics.Flush();// イメージの座標は左上が(0,0)だが、スライドは左下が(0,0)// このまま表示すると上下反転するので修正するretBitmap.RotateFlip(RotateFlipType.RotateNoneFlipY);return (retBitmap);}// インデックスカラーのRGB値テーブル (0:黒から255:白まで)private byte[] tbl = new byte[] {0, 0, 0,255, 0, 0,255, 255, 0,0, 255, 0,0, 255, 255,0, 0, 255,255, 0, 255,255, 255, 255,128, 128, 128,192, 192, 192,255, 0, 0,255, 127, 127,204, 0, 0,204, 102, 102,153, 0, 0,153, 76, 76,127, 0, 0,127, 63, 63,76, 0, 0,76, 38, 38,255, 63, 0,255, 159, 127,204, 51, 0,204, 127, 102,153, 38, 0,153, 95, 76,127, 31, 0,127, 79, 63,76, 19, 0,76, 47, 38,255, 127, 0,255, 191, 127,204, 102, 0,204, 153, 102,153, 76, 0,153, 114, 76,127, 63, 0,127, 95, 63,76, 38, 0,76, 57, 38,255, 191, 0,255, 223, 127,204, 153, 0,204, 178, 102,153, 114, 0,153, 133, 76,127, 95, 0,127, 111, 63,76, 57, 0,76, 66, 38,255, 255, 0,255, 255, 127,204, 204, 0,204, 204, 102,153, 153, 0,153, 153, 76,127, 127, 0,127, 127, 63,76, 76, 0,76, 76, 38,191, 255, 0,223, 255, 127,153, 204, 0,178, 204, 102,114, 153, 0,133, 153, 76,95, 127, 0,111, 127, 63,57, 76, 0,66, 76, 38,127, 255, 0,191, 255, 127,102, 204, 0,153, 204, 102,76, 153, 0,114, 153, 76,63, 127, 0,95, 127, 63,38, 76, 0,57, 76, 38,63, 255, 0,159, 255, 127,51, 204, 0,127, 204, 102,38, 153, 0,95, 153, 76,31, 127, 0,79, 127, 63,19, 76, 0,47, 76, 38,0, 255, 0,127, 255, 127,0, 204, 0,102, 204, 102,0, 153, 0,76, 153, 76,0, 127, 0,63, 127, 63,0, 76, 0,38, 76, 38,0, 255, 63,127, 255, 159,0, 204, 51,102, 204, 127,0, 153, 38,76, 153, 95,0, 127, 31,63, 127, 79,0, 76, 19,38, 76, 47,0, 255, 127,127, 255, 191,0, 204, 102,102, 204, 153,0, 153, 76,76, 153, 114,0, 127, 63,63, 127, 95,0, 76, 38,38, 76, 57,0, 255, 191,127, 255, 223,0, 204, 153,102, 204, 178,0, 153, 114,76, 153, 133,0, 127, 95,63, 127, 111,0, 76, 57,38, 76, 66,0, 255, 255,127, 255, 255,0, 204, 204,102, 204, 204,0, 153, 153,76, 153, 153,0, 127, 127,63, 127, 127,0, 76, 76,38, 76, 76,0, 191, 255,127, 223, 255,0, 153, 204,102, 178, 204,0, 114, 153,76, 133, 153,0, 95, 127,63, 111, 127,0, 57, 76,38, 66, 76,0, 127, 255,127, 191, 255,0, 102, 204,102, 153, 204,0, 76, 153,76, 114, 153,0, 63, 127,63, 95, 127,0, 38, 76,38, 57, 76,0, 63, 255,127, 159, 255,0, 51, 204,102, 127, 204,0, 38, 153,76, 95, 153,0, 31, 127,63, 79, 127,0, 19, 76,38, 47, 76,0, 0, 255,127, 127, 255,0, 0, 204,102, 102, 204,0, 0, 153,76, 76, 153,0, 0, 127,63, 63, 127,0, 0, 76,38, 38, 76,63, 0, 255,159, 127, 255,51, 0, 204,127, 102, 204,38, 0, 153,95, 76, 153,31, 0, 127,79, 63, 127,19, 0, 76,47, 38, 76,127, 0, 255,191, 127, 255,102, 0, 204,153, 102, 204,76, 0, 153,114, 76, 153,63, 0, 127,95, 63, 127,38, 0, 76,57, 38, 76,191, 0, 255,223, 127, 255,153, 0, 204,178, 102, 204,114, 0, 153,133, 76, 153,95, 0, 127,111, 63, 127,57, 0, 76,66, 38, 76,255, 0, 255,255, 127, 255,204, 0, 204,204, 102, 204,153, 0, 153,153, 76, 153,127, 0, 127,127, 63, 127,76, 0, 76,76, 38, 76,255, 0, 191,255, 127, 223,204, 0, 153,204, 102, 178,153, 0, 114,153, 76, 133,127, 0, 95,127, 63, 111,76, 0, 57,76, 38, 66,255, 0, 127,255, 127, 191,204, 0, 102,204, 102, 153,153, 0, 76,153, 76, 114,127, 0, 63,127, 63, 95,76, 0, 38,76, 38, 57,255, 0, 63,255, 127, 159,204, 0, 51,204, 102, 127,153, 0, 38,153, 76, 95,127, 0, 31,127, 63, 79,76, 0, 19,76, 38, 47,51, 51, 51,91, 91, 91,132, 132, 132,173, 173, 173,214, 214, 214,255, 255, 255};/// <summary>/// 色番号からペン色を取得/// </summary>/// <param name="index">色番号</param>/// <returns></returns>private Color fromColorIndex(ushort index){Color col = Color.FromName("red");if (index >= 0 && index <= 255){index *= 3;col = Color.FromArgb(tbl[index], tbl[index + 1], tbl[index + 2]);}return col;}}}
0 件のコメント:
コメントを投稿