Using WPF technology, the development of electronic document reader OFD

Introduction  OFD is the national standard layout document format, it came into force in 2016. OFD documentation national standards refer to "electronic document storage and exchange format layout document." Since it is a national standard, OFD then certainly in the first government system, and gradually to all aspects of society. OFD is present in the study of various types of file formats, the introduction of standards, has the following advantages:

1 property rights belong to independent property rights

2 portability: small files and large compressibility ratio. Tests show that the generated PDF file is smaller than the body.

3 is open: Getting started is easy for a user to more openness.

4 scalable: Reserved inlet and scalable custom indexing references arranged non-contact mechanism, to support the characterization.

5 rendering device-independent, read on various devices, printing or printing, layout fixed, do not run version.

6 widely applied: whether it is e-commerce, electronic public service, or information dissemination, file exchange, file management and so need to support the layout of the document.

  About standards, I have to Tucao about. OFD standard is several domestic professional electronic document processing company involved in the drafting; standard document (Note: The following with "standard" criteria specific to OFD) only 126, in my opinion, the standard description of the technical details too simple, no some technical background is difficult to understand. This is in sharp contrast to the standard pdf, there are more than 1,000 pages. I did not find the text in the online version of the standard, especially not conducive to reading and reference.

  I have recently been studying ofd standard, trying to write a reader, already beginning to bear fruit, the interface is as follows:

Reader Download  https://download.csdn.net/download/qq_29939347/11799156

 

 I put the paper process developed to make a brief introduction.

OFD standard profiles

  Briefly, the OFD storage is the use of compression technology, is described in XML format. This Microsoft word document (docx) format is very similar. Standard reference may be Microsoft's approach; but also technically realistic, GB This format is not original and leading. After the OFD unzip the file format, see the following directories and files:

 

File will include resource files (images, fonts, libraries, etc.). XML will be stored resources, primitives (text, images, etc.) do show description, reading software will show a consistent display these descriptions.

 

OFD reading software development steps

  Domestic popular ofd Foxit reader software should be developed in several subjects, I have used both. I would like to Tucao about:

  1) Foxit Reader is ofd help document format, but can not be opened with the number of families reader.

  2) Some ofd document xml tag, can not find in the standard, some companies are original?

  The software is written in C ++ and uses QT. Under the same circumstances, compared to C #, C ++ software development will certainly increase the difficulty. In the windows interface development platform, WPF is the best of the library. WPF despite more than ten years, it seems we are still unfamiliar with this. BS is now mainly dominated; WPF is not good enough, is untimely.

1 pair OFD file decompression

  OFD document was in fact a compressed file, unzip files have directory structure. The module's function is to obtain the data path and each file.

using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;

namespace WpfOfdReader.OfdFileType
{
    class OfdFileReader
    {
        ZipArchive _zipArchive;
        public void ReadZipFile(string fileName)
        {
            _zipArchive = ZipFile.OpenRead(fileName);
        }

        public void Close()
        {
            if (_zipArchive != null)
                _zipArchive.Dispose();
        }

        public List<OfdFileItemInfo> AllFileItem
        {
            get
            {
                return _zipArchive.Entries.Select(o => new OfdFileItemInfo(o)).ToList();
            }
        }

        private ZipArchiveEntry GetArchiveEntry(ZipFilePath path)
        {
            foreach (ZipArchiveEntry entry in _zipArchive.Entries)
            {
                if (entry.FullName == path.FulleName)
                {
                    return entry;
                }
            }
            return null;
        }

        public static byte[] GetFileBuffer(ZipArchiveEntry entry)
        {
            List<byte[]> listBuffer = new List<byte[]>();
            using (Stream s = entry.Open())
            {
                while (true)
                {
                    byte[] buffer = new byte[10];
                    int n = s.Read(buffer, 0, buffer.Length);
                    if (n <= 0)
                        break;

                    if (n == buffer.Length)
                    {
                        listBuffer.Add(buffer);
                    }
                    else
                    {
                        Array.Resize(ref buffer, n);
                        listBuffer.Add(buffer);
                        break;
                    }
                }
            }

            int totalLen = 0;
            listBuffer.ForEach(o => totalLen += o.Length);
            byte[] result = new byte[totalLen];
            int index = 0;
            foreach (byte[] buffer in listBuffer)
            {
                Buffer.BlockCopy(buffer, 0, result, index, buffer.Length);
                index += buffer.Length;
            }
            return result;
        }
    }
}

 2 shows the need to find the page

  Along the route OFD.xml -> Document.xml -> Pages, find the page needs to show the final page. Page page contains three types of nodes: TextObject, PathObject, ImageObject, cum corresponding to three elements in the standard. We need to model these three types of nodes. These three classes of common inherited from the parent class PageObject. All elements are drawing area, coordinate conversion, clipping, etc. in common, all these processes the PageObject class.

    public class PageObject
    {
        public string ID { get; set; }
        public PageLayer ParentLayer { get; set; }
        public string PageFileLoc => ParentLayer.ParentPage.PageFileLoc;

        XmlNode _xmlNode;

        public string Boundary { get; set; }
        public string CTM { get; set; }

        public OfdClipsGroup ClipsGroup { get; set; }

        public void SetPageObject(PageLayer layer, XmlNode xmlNode)
        {
            _xmlNode = xmlNode;

            ID = XmlHelper.GetXmlAttributeValue(xmlNode, "ID");
            ParentLayer = layer;

            Boundary = XmlHelper.GetXmlAttributeValue(xmlNode, "Boundary");
            CTM = XmlHelper.GetXmlAttributeValue(xmlNode, "CTM");

            foreach (XmlNode childNode in xmlNode.ChildNodes)
            {
                if (childNode.Name == OfdClipsGroup.XML_Name)
                {
                    ClipsGroup = OfdClipsGroup.FromXml(childNode);
                    break;
                }
            }

        }

        public string GetAttributeValue(string name)
        {
            string result = XmlHelper.GetXmlAttributeValue(_xmlNode, name);
            return result;
        }

    }

 3 Create WPF display model

Image pinpoint the need to use a Canvas as a container. Draw the need to use a lot of graphics to draw a lightweight model DrawingVisual. On this basis, rendering the base model derived OfdVisual, this model corresponds PageObject. 

    public class OfdVisual : DrawingVisual
    {
        public OfdVisual()
        {
        }

        protected DrawingCanvas _drawingCanvas;
        public DrawingCanvas DrawingCanvas
        {
            get
            {
                return _drawingCanvas;
            }
        }

        public bool IsAddToCanvas
        {
            get
            {
                return _drawingCanvas != null;
            }
        }


        internal void AddToCanvas(DrawingCanvas drawingCanvas)
        {
            if (_drawingCanvas == drawingCanvas)
                return;
            _drawingCanvas = drawingCanvas;
            _drawingCanvas.AddVisual(this);
        }

        public void ReomveFromCanvas()
        {
            if (_drawingCanvas != null)
            {
                _drawingCanvas.DeleteVisual(this);
            }
        }

        public virtual void Show(bool visiable, bool even = false)
        {

        }

        public Point BoundaryLocation { get; set; }
        public Size BoundarySize { get; set; }

        public MatrixTransform ObjectTransform { get; protected set; }

        public VisualClipsGroup ObjectClipsGroup { get; protected set; }
        public void SetPageObject(PageObject pageObject)
        {
            OfdHelper.ParseBoundary(pageObject.Boundary, out Point location, out Size size);
            BoundaryLocation = location;
            BoundarySize = size;

            if (!string.IsNullOrEmpty(pageObject.CTM))
            {
                ObjectTransform = OfdHelper.OfdTextToTransform(pageObject.CTM);
            }

            if (pageObject.ClipsGroup != null)
            {
                ObjectClipsGroup = new VisualClipsGroup() { ClipsGroup = pageObject.ClipsGroup };
            }
        }

        protected Rect ClipRect
        {
            get
            {
                return new Rect(0, 0, BoundarySize.Width, BoundarySize.Height);
            }
        }

        protected RectangleGeometry ClipGeometry
        {
            get
            {
                RectangleGeometry geometry = new RectangleGeometry(ClipRect);
                return geometry;
            }
        }


        protected void PutBoundary(DrawingContext dc)
        {
            TranslateTransform translateBoundary = new TranslateTransform(BoundaryLocation.X, BoundaryLocation.Y);
            dc.PushTransform(translateBoundary);
            dc.PushClip(ClipGeometry);
        }

        protected void PopBoundary(DrawingContext dc)
        {
            dc.Pop();
            dc.Pop();
        }

        protected void PutTransform(DrawingContext dc)
        {
            if (ObjectTransform != null)
            {
                dc.PushTransform(ObjectTransform);
            }
        }

        protected void PopTransform(DrawingContext dc)
        {
            if (ObjectTransform != null)
            {
                dc.Pop();
            }
        }
    }

There are three types of drawing objects OfdVisualText, OfdVisualPath, OfdVisualImage, derived from OfdVisual. We were treated three kinds of primitive data. All drawing operations in the function

public override void Show(bool visiable, bool even = false);

The corresponding text, drawing functions as follows:

 void DrawText()
        {
            using (DrawingContext dc = RenderOpen())
            {
                if (ObjectClipsGroup == null)
                {
                    PutBoundary(dc);
                    PutTransform(dc);

                    DrawTextInner(dc);

                    PopTransform(dc);
                    PopBoundary(dc);
                }
                else
                {
                    foreach (VisulClip visulClip in ObjectClipsGroup)
                    {
                        PutBoundary(dc);
                        visulClip.PutClip(dc);
                        PutTransform(dc);

                        DrawTextInner(dc);

                        PopTransform(dc);
                        visulClip.PopClip(dc);
                        PopBoundary(dc);
                    }
                }
            }
        }

        private void DrawTextInner(DrawingContext dc)
        {
            int i = -1;
            double deltaXTotal = 0;
            double deltaYTotal = 0;
            Point pt = new Point();

            foreach (FormattedText formattedText in FormattedTextCollection)
            {
                i++;
                if (i != 0)
                {
                    if (DeltaCollectionX != null)
                    {
                        double deltaX = DeltaCollectionX.GetValue(i - 1);
                        deltaXTotal += deltaX;
                    }

                    if (DeltaCollectionY != null)
                    {
                        double deltaY = DeltaCollectionY.GetValue(i - 1);
                        deltaYTotal += deltaY;
                    }
                }

                pt.X = TextLocation.X + deltaXTotal;
                pt.Y = TextLocation.Y + deltaYTotal - FormattedTextCollection.FontBaseLine;
                dc.DrawText(formattedText, pt);
            }
        }

 Before drawing, it is necessary to do translation, rotation and shearing operation on the current coordinates.

Postscript key reader writing class software modeling. First read standards, as described in standard primitives do classification analysis, and to establish the corresponding display model. I do WPF development for many years, I feel with WPF development of such software is not very difficult. I used less than two weeks, initially completed OFD Display Development. If you want to complete implementation of OFD standards, but also requires a lot of development, I will gradually improve the functionality of the software.

Guess you like

Origin www.cnblogs.com/yuanchenhui/p/ofdreader.html