첨부 실행 코드는 나눔고딕코딩 폰트를 사용합니다.
본 블로그는 광고를 포함하고 있습니다.
광고 클릭에서 발생하는 수익금은 모두 블로그 콘텐츠 향상을 위해 쓰여집니다.

728x90
반응형
728x170

TestProject.zip
다운로드
result.xps
다운로드

▶ PlainTextDocumentPaginator.cs

using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Printing;
using System.Windows;
using System.Windows.Documents;
using System.Windows.Media;

namespace TestProject
{
    /// <summary>
    /// 단순 텍스트 문서 페이지 지정자
    /// </summary>
    public class PlainTextDocumentPaginator : DocumentPaginator
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Declaration
        ////////////////////////////////////////////////////////////////////////////////////////// Private

        #region Class

        /// <summary>
        /// 프린트 라인
        /// </summary>
        private class PrintLine
        {
            //////////////////////////////////////////////////////////////////////////////////////////////////// Field
            ////////////////////////////////////////////////////////////////////////////////////////// Public

            #region Field

            /// <summary>
            /// 문자열
            /// </summary>
            public string String;

            /// <summary>
            /// 플래그
            /// </summary>
            public bool Flag;

            #endregion

            //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
            ////////////////////////////////////////////////////////////////////////////////////////// Public

            #region 생성자 - PrintLine(source, flag)

            /// <summary>
            /// 생성자
            /// </summary>
            /// <param name="source">소스 문자열</param>
            /// <param name="flag">플래그</param>
            public PrintLine(string source, bool flag)
            {
                String = source;
                Flag   = flag;
            }

            #endregion
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Field
        ////////////////////////////////////////////////////////////////////////////////////////// Private

        #region Field

        /// <summary>
        /// 중단 문자 배열
        /// </summary>
        private char[] breakCharacterArray = new char[] { ' ', '-' };

        /// <summary>
        /// 텍스트
        /// </summary>
        private string text = string.Empty;

        /// <summary>
        /// 헤더 텍스트
        /// </summary>
        private string headerText = null;

        /// <summary>
        /// 타입 페이스
        /// </summary>
        private Typeface typeface = new Typeface("");

        /// <summary>
        /// EM 크기
        /// </summary>
        private double emSize = 11;

        /// <summary>
        /// 페이지 크기
        /// </summary>
        private Size pageSize = new Size(8.5d * 96d, 11d * 96d);

        /// <summary>
        /// 최대 크기
        /// </summary>
        private Size maximumSize = new Size(0, 0);

        /// <summary>
        /// 마진 두께
        /// </summary>
        private Thickness marginThickness = new Thickness(96d);

        /// <summary>
        /// 프린트 티켓
        /// </summary>
        private PrintTicket printTicket = new PrintTicket();

        /// <summary>
        /// 텍스트 랩핑
        /// </summary>
        private TextWrapping textWrapping = TextWrapping.Wrap;

        /// <summary>
        /// 문서 페이지 리스트
        /// </summary>
        private List<DocumentPage> documentPageList;

        /// <summary>
        /// 테두리 펜
        /// </summary>
        private Pen borderPen = new Pen(Brushes.Transparent, 1);

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Property
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 텍스트 - Text

        /// <summary>
        /// 텍스트
        /// </summary>
        public string Text
        {
            set
            {
                this.text = value;
            }
            get
            {
                return this.text;
            }
        }

        #endregion
        #region 텍스트 랩핑 - TextWrapping

        /// <summary>
        /// 텍스트 랩핑
        /// </summary>
        public TextWrapping TextWrapping
        {
            set
            {
                this.textWrapping = value;
            }
            get
            {
                return this.textWrapping;
            }
        }

        #endregion
        #region 여백 - Margin

        /// <summary>
        /// 여백
        /// </summary>
        public Thickness Margin
        {
            set
            {
                this.marginThickness = value;
            }
            get
            {
                return this.marginThickness;
            }
        }

        #endregion
        #region 타입 페이스 - Typeface

        /// <summary>
        /// 타입 페이스
        /// </summary>
        public Typeface Typeface
        {
            set
            {
                this.typeface = value;
            }
            get
            {
                return this.typeface;
            }
        }

        #endregion
        #region EM 크기 - EMSize

        /// <summary>
        /// EM 크기
        /// </summary>
        public double EMSize
        {
            set
            {
                this.emSize = value;
            }
            get
            {
                return this.emSize;
            }
        }

        #endregion
        #region 프린트 티켓 - PrintTicket

        /// <summary>
        /// 프린트 티켓
        /// </summary>
        public PrintTicket PrintTicket
        {
            set
            {
                this.printTicket = value;
            }
            get
            {
                return this.printTicket;
            }
        }

        #endregion
        #region 헤더 텍스트 - HeaderText

        /// <summary>
        /// 헤더 텍스트
        /// </summary>
        public string HeaderText
        {
            set
            {
                this.headerText = value;
            }
            get
            {
                return this.headerText;
            }
        }

        #endregion
        #region 페이지 수 유효 여부 - IsPageCountValid

        /// <summary>
        /// 페이지 수 유효 여부
        /// </summary>
        public override bool IsPageCountValid
        {
            get
            {
                if(this.documentPageList == null)
                {
                    Format();
                }

                return true;
            }
        }

        #endregion
        #region 페이지 수 - PageCount

        /// <summary>
        /// 페이지 수
        /// </summary>
        public override int PageCount
        {
            get
            {
                if(this.documentPageList == null)
                {
                    return 0;
                }

                return this.documentPageList.Count;
            }
        }

        #endregion
        #region 페이지 크기 - PageSize

        /// <summary>
        /// 페이지 크기
        /// </summary>
        public override Size PageSize
        {
            set
            {
                this.pageSize = value;
            }
            get
            {
                return this.pageSize;
            }
        }

        #endregion
        #region 소스 - Source

        /// <summary>
        /// 소스
        /// </summary>
        public override IDocumentPaginatorSource Source
        {
            get
            {
                return null;
            }
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 페이지 구하기 - GetPage(pageNumber)

        /// <summary>
        /// 페이지 구하기
        /// </summary>
        /// <param name="pageNumber">페이지 번호</param>
        /// <returns>DocumentPage 객체</returns>
        public override DocumentPage GetPage(int pageNumber)
        {
            return this.documentPageList[pageNumber];
        }

        #endregion
        #region FormattedText 객체 구하기 - GetFormattedText(text)

        /// <summary>
        /// FormattedText 객체 구하기
        /// </summary>
        /// <param name="text">테스트</param>
        /// <returns>FormattedText 객체</returns>
        private FormattedText GetFormattedText(string text)
        {
            return new FormattedText
            (
                text,
                CultureInfo.CurrentCulture,
                FlowDirection.LeftToRight,
                this.typeface,
                this.emSize,
                Brushes.Black
            );
        }

        #endregion
        #region 라인 처리하기 - ProcessLine(sourceLine, printableWidth, printLineList)

        /// <summary>
        /// 라인 처리하기
        /// </summary>
        /// <param name="sourceLine">소스 라인</param>
        /// <param name="printableWidth">인쇄 가능한 너비</param>
        /// <param name="printLineList">프린트 라인 리스트</param>
        private void ProcessLine(string sourceLine, double printableWidth, List<PrintLine> printLineList)
        {
            sourceLine = sourceLine.TrimEnd(' ');

            if(TextWrapping == TextWrapping.NoWrap)
            {
                #region TextWrapping.NoWrap

                do
                {
                    int length = sourceLine.Length;

                    while(GetFormattedText(sourceLine.Substring(0, length)).Width > printableWidth)
                    {
                        length--;
                    }

                    printLineList.Add(new PrintLine(sourceLine.Substring(0, length), length < sourceLine.Length));

                    sourceLine = sourceLine.Substring(length);
                }
                while(sourceLine.Length > 0);

                #endregion
            }
            else
            {
                #region TextWrapping.Wrap, TextWrapping.WrapWithOverflow

                do
                {
                    int  length = sourceLine.Length;
                    bool flag   = false;

                    while(GetFormattedText(sourceLine.Substring(0, length)).Width > printableWidth)
                    {
                        int index = sourceLine.LastIndexOfAny(this.breakCharacterArray, length - 2);

                        if(index != -1)
                        {
                            length = index + 1;
                        }
                        else
                        {
                            index = sourceLine.IndexOfAny(this.breakCharacterArray);

                            if(index != -1)
                            {
                                length = index + 1;
                            }

                            if(TextWrapping == TextWrapping.Wrap)
                            {
                                while(GetFormattedText(sourceLine.Substring(0, length)).Width > printableWidth)
                                {
                                    length--;
                                }

                                flag = true;
                            }

                            break;
                        }
                    }

                    printLineList.Add(new PrintLine(sourceLine.Substring(0, length), flag));

                    sourceLine = sourceLine.Substring(length);
                }
                while(sourceLine.Length > 0);

                #endregion
            }
        }

        #endregion
        #region 포맷하기 - Format()

        /// <summary>
        /// 포맷하기
        /// </summary>
        private void Format()
        {
            List<PrintLine> printLineList = new List<PrintLine>();

            FormattedText sampleFormattedText = GetFormattedText("W");

            double printableWidth = PageSize.Width - Margin.Left - Margin.Right;

            if(printableWidth < sampleFormattedText.Width)
            {
                return;
            }

            string       sourceLine;
            Pen          pen          = new Pen(Brushes.Black, 2);
            StringReader stringReader = new StringReader(this.text);

            while(null != (sourceLine = stringReader.ReadLine()))
            {
                ProcessLine(sourceLine, printableWidth, printLineList);
            }

            stringReader.Close();

            double lineHeight      = sampleFormattedText.LineHeight + sampleFormattedText.Height;
            double printableHeight = PageSize.Height - Margin.Top - Margin.Bottom;
            int    pageLineCount   = (int)(printableHeight / lineHeight);

            if(pageLineCount < 1)
            {
                return;
            }

            int    pageCount = (printLineList.Count + pageLineCount - 1) / pageLineCount;
            double startX    = Margin.Left;
            double startY    = Margin.Top;

            this.documentPageList = new List<DocumentPage>();

            for(int page = 0, line = 0; page < pageCount; page++)
            {
                DrawingVisual drawingVisual = new DrawingVisual();

                DrawingContext drawingContext = drawingVisual.RenderOpen();

                #region 페이지 내 일정 영역만 출력하면 페이지가 정상적으로 출력되지 않기 때문에 아래 코드를 실행한다.

                drawingContext.DrawRectangle(Brushes.Transparent, this.borderPen, new Rect(PageSize));

                #endregion

                if(HeaderText != null && HeaderText.Length > 0)
                {
                    FormattedText formattedText = GetFormattedText(HeaderText);

                    formattedText.SetFontWeight(FontWeights.Bold);

                    Point textPoint = new Point(startX, startY - 2 * formattedText.Height);

                    drawingContext.DrawText(formattedText, textPoint);
                }

                if(pageCount > 1)
                {
                    FormattedText formattedText = GetFormattedText("Page " + (page + 1) + " of " + pageCount);

                    formattedText.SetFontWeight(FontWeights.Bold);

                    Point textPoint = new Point
                    (
                        (PageSize.Width + Margin.Left - Margin.Right - formattedText.Width) / 2d,
                        PageSize.Height - Margin.Bottom + formattedText.Height
                    );

                    drawingContext.DrawText(formattedText, textPoint);
                }

                for(int i = 0; i < pageLineCount; i++, line++)
                {
                    if(line == printLineList.Count)
                    {
                        break;
                    }

                    string lineString = printLineList[line].String;

                    FormattedText lineFormattedText = GetFormattedText(lineString);

                    Point textPoint = new Point(startX, startY + i * lineHeight);

                    drawingContext.DrawText(lineFormattedText, textPoint);

                    if(printLineList[line].Flag)
                    {
                        double x      = startX + printableWidth + 6;
                        double y      = startY + i * lineHeight + lineFormattedText.Baseline;
                        double length = this.typeface.CapsHeight * this.emSize;

                        drawingContext.DrawLine(pen, new Point(x, y), new Point(x + length     , y - length     ));
                        drawingContext.DrawLine(pen, new Point(x, y), new Point(x              , y - length / 2d));
                        drawingContext.DrawLine(pen, new Point(x, y), new Point(x + length / 2d, y              ));
                    }
                }

                drawingContext.Close();

                DocumentPage documentPage = new DocumentPage(drawingVisual);

                this.documentPageList.Add(documentPage);
            }

            stringReader.Close();
        }

        #endregion
    }
}

 

▶ MainWindow.xaml

<Window x:Class="TestProject.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Width="800"
    Height="600"
    Title="DocumentPaginator 클래스 : 일반 텍스트 문자열 출력하기"
    FontFamily="나눔고딕코딩"
    FontSize="16">
    <Grid>
        <StackPanel
            HorizontalAlignment="Center"
            VerticalAlignment="Center">
            <TextBox Name="textBox"
                Margin="10"
                Width="300"
                Height="300"
                VerticalContentAlignment="Top"
                AcceptsReturn="True" />
            <Button Name="printButton"
                Margin="10"
                Width="100"
                Height="30"
                Content="인쇄하기" />
        </StackPanel>
    </Grid>
</Window>

 

▶ MainWindow.xaml.cs

using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

namespace TestProject
{
    /// <summary>
    /// 메인 윈도우
    /// </summary>
    public partial class MainWindow : Window
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 생성자 - MainWindow()

        /// <summary>
        /// 생성자
        /// </summary>
        public MainWindow()
        {
            InitializeComponent();

            this.printButton.Click += printButton_Click;
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method
        ////////////////////////////////////////////////////////////////////////////////////////// Private

        #region 인쇄하기 버튼 클릭시 처리하기 - printButton_Click(sender, e)

        /// <summary>
        /// 인쇄하기 버튼 클릭시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void printButton_Click(object sender, RoutedEventArgs e)
        {
            PrintDialog printDialog = new PrintDialog();

            if(printDialog.ShowDialog().GetValueOrDefault())
            {
                PlainTextDocumentPaginator paginator = new PlainTextDocumentPaginator();

                paginator.PrintTicket = printDialog.PrintTicket;
                paginator.Text        = this.textBox.Text;
                paginator.HeaderText  = string.Empty;
                paginator.Typeface    = new Typeface
                (
                    textBox.FontFamily,
                    textBox.FontStyle,
                    textBox.FontWeight,
                    textBox.FontStretch
                );

                paginator.EMSize       = this.textBox.FontSize;
                paginator.TextWrapping = this.textBox.TextWrapping;
                paginator.Margin       = new Thickness(48);
                paginator.PageSize     = new Size
                (
                    printDialog.PrintableAreaWidth,
                    printDialog.PrintableAreaHeight
                );

                printDialog.PrintDocument(paginator, "Sample");
            }
        }

        #endregion
    }
}
728x90
반응형
그리드형
Posted by 사용자 icodebroker
TAG , ,

댓글을 달아 주세요