本篇文章將介紹開發醫學影像膠片列印系統(printscu模式)遇到不規則排版時的一種思路,
一般來講,醫院列印膠片時都是整張膠片列印,但有時需要將多個病人或一個病人的多個檢查列印在同一張膠片上,
這時候就需要不規則排版來滿足列印需求,使膠片利用率最大化。
國際慣例,先看效果:
常規列印業務流程:
1、編輯佈局模板
2、載入佈局模板
3、選擇標記模板
4、下載與選擇影像
5、微調影像
6、超清預覽、傳送列印
編輯佈局模板:
我們在一個Grid中,通過行數和列數迴圈建立帶邊框的Border來顯示錶格,並新增滑鼠事件:
for (int i = 0; i < row; i++) { for (int j = 0; j < col; j++) { Border border = new Border { Width = w, Height = h, HorizontalAlignment = HorizontalAlignment.Left, VerticalAlignment = VerticalAlignment.Top, Margin = new Thickness(j * w, i * h, 0, 0), BorderThickness = new Thickness(1), BorderBrush = ColorHandler.GetColorBrush("#CCCCCC"), Background = ColorHandler.GetColorBrush("#000000"), }; border.MouseEnter += Border_MouseEnter; border.MouseLeftButtonDown += Border_MouseLeftButtonDown; GridTempl.Children.Add(border); } }
點選單元格時將改變背景顏色,在滑鼠按下時並移動滑鼠,觸發MouseEnter,選擇多個單元格:
因為合併單元格是不能為不規則形狀,所以多選的單元格整體必須為一個矩形,
因此多選時首先記錄所有選中的單元格,然後通過座標判斷左上角和右下角的單元格位置,這樣整體矩形的寬和高的範圍就確定了,
在此矩形範圍內的單元格將自動全部選中:
但也有特殊情況:如果矩形範圍包含大小不一的單元格 這時候計算範圍就會不準確:
通過以下幾種情況來判斷大單元格與小單元格的包含關係:
/// <summary> /// 篩選出已經合併的cell並計算最大選中範圍 /// </summary> private void CheckCell() { List<Border> bors = new List<Border>(); for (int i = 0; i < GridTempl.Children.Count; i++) { Border border = (GridTempl.Children[i] as Border); if (((SolidColorBrush)border.Background).Color == Color.FromRgb(68, 68, 68)) { bors.Add(border); } } double cellMinLeft = bors[0].Margin.Left; double cellMaxLeft = 0; double cellMinTop = bors[0].Margin.Top; double cellMaxTop = 0; for (int i = 0; i < bors.Count; i++) { if (bors[i].Margin.Left < cellMinLeft) { cellMinLeft = bors[i].Margin.Left; } if (bors[i].Margin.Top < cellMinTop) { cellMinTop = bors[i].Margin.Top; } if (bors[i].Margin.Top + bors[i].Height > cellMaxTop) { cellMaxTop = bors[i].Margin.Top + bors[i].Height; } if (bors[i].Margin.Left + bors[i].Width > cellMaxLeft) { cellMaxLeft = bors[i].Margin.Left + bors[i].Width; } } for (int i = 0; i < GridTempl.Children.Count; i++) { Border otherBor = GridTempl.Children[i] as Border; if (bors.Contains(otherBor)) { continue; } //包含左上角 if (otherBor.Margin.Left > cellMinLeft && (otherBor.Margin.Left) < cellMaxLeft && otherBor.Margin.Top > cellMinTop && (otherBor.Margin.Top) < cellMaxTop) { otherBor.Background = ColorHandler.GetColorBrush("#444444"); CheckCell(); return; } //包含右上角 if (otherBor.Margin.Left + otherBor.Width > cellMinLeft && (otherBor.Margin.Left + otherBor.Width) < cellMaxLeft && otherBor.Margin.Top > cellMinTop && (otherBor.Margin.Top) < cellMaxTop) { otherBor.Background = ColorHandler.GetColorBrush("#444444"); CheckCell(); return; } //包含右下角 if (otherBor.Margin.Left + otherBor.Width > cellMinLeft && (otherBor.Margin.Left + otherBor.Width) < cellMaxLeft && (otherBor.Margin.Top + otherBor.Height) > cellMinTop && (otherBor.Margin.Top + otherBor.Height) < cellMaxTop) { otherBor.Background = ColorHandler.GetColorBrush("#444444"); CheckCell(); return; } //包含左下角 if (otherBor.Margin.Left > cellMinLeft && (otherBor.Margin.Left) < cellMaxLeft && (otherBor.Margin.Top + otherBor.Height) > cellMinTop && (otherBor.Margin.Top + otherBor.Height) < cellMaxTop) { otherBor.Background = ColorHandler.GetColorBrush("#444444"); CheckCell(); return; } //水平分割 if (otherBor.Margin.Left > cellMinLeft && (otherBor.Margin.Left) < cellMaxLeft && (otherBor.Margin.Top) <= cellMinTop && (otherBor.Margin.Top + otherBor.Height) >= cellMaxTop) { otherBor.Background = ColorHandler.GetColorBrush("#444444"); CheckCell(); return; } //垂直分割 if (otherBor.Margin.Left <= cellMinLeft && (otherBor.Margin.Left + otherBor.Width) >= cellMaxLeft && (otherBor.Margin.Top) > cellMinTop && (otherBor.Margin.Top + otherBor.Height) < cellMaxTop) { otherBor.Background = ColorHandler.GetColorBrush("#444444"); CheckCell(); return; } } }
通過遞迴填充單元格達到矩形範圍的同行同列自動選擇,接下來就可以合併所選擇的單元格:
計算最大寬度和最大高度,並且使左上角的單元格等於最大寬高,以實現合併效果:
//計算最大寬度 double w = borderFirst.Width; for (int i = 0; i < bors.Count; i++) { if (bors[i] != borderFirst && borderFirst.Margin.Top == bors[i].Margin.Top) { w += bors[i].Width; } } //計算最大高度 double h = borderFirst.Height; for (int i = 0; i < bors.Count; i++) { if (bors[i] != borderFirst && borderFirst.Margin.Left == bors[i].Margin.Left) { h += bors[i].Height; } } borderFirst.Tag = Math.Round(h / borderFirst.Height) + "#" + Math.Round(w / borderFirst.Width); borderFirst.Width = w; borderFirst.Height = h;
看效果:
將佈局通過自定義格式儲存到本地檔案,就可以在排版介面載入佈局模板。
編輯標記模板:
選擇常用Tag新增到膠片的四個角,以便在後面載入影像的時候讀取標記資訊:
讀取檢查列表和下載影像:
可以參考本系列教程文章:
C#開發PACS醫學影像處理系統(五):查詢病人資訊列表
載入影像並微調(平移,縮放,自由旋轉等二維操作):
使用1:1畫素超清預覽檢視列印細節:
下載一個列印服務端模擬接受列印:
我這裡使用的是模擬鐳射相機5.0版本,下載地址:https://www.fxxz.com/soft/47115.html
設定好埠併傳送,檢視握手狀態和通訊包:
檢視列印結果: