2019年10月5日土曜日

SlideImageReader.cs

AutoCADスライドまたはスライドライブラリファイルをSystem.Drawing.Bitmap に変換するクラス。
使い方
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 件のコメント:

コメントを投稿

異尺度注釈図形にアタッチされている尺度を知る

 異尺度注釈図形が持っている尺度(文字列)を表示する ;;; ;;; LISTANNOSCALE.LSP ;;; (defun C:LISTANNOSCALE ( / el id f)   (setq f T)   ;異尺度注釈図形を選択   (if (setq el (entg...