Exemple #1
0
        /// <summary>
        /// Render the specified region to an image of the specified size, split in a number of tiles equal to the number of threads used by this <see cref="MuPDFMultiThreadedPageRenderer"/>, without marshaling. This method will not return until all the rendering threads have finished.
        /// </summary>
        /// <param name="targetSize">The total size of the image that should be rendered.</param>
        /// <param name="region">The region in page units that should be rendered.</param>
        /// <param name="destinations">An array containing the addresses of the buffers where the rendered tiles will be written. There must be enough space available in each buffer to write the values for all the pixels of the tile, otherwise this will fail catastrophically!
        /// As long as the <paramref name="targetSize"/> is the same, the size in pixel of the tiles is guaranteed to also be the same.</param>
        /// <param name="pixelFormat">The format of the pixel data.</param>
        public void Render(RoundedSize targetSize, Rectangle region, IntPtr[] destinations, PixelFormats pixelFormat)
        {
            if (destinations.Length != Contexts.Length)
            {
                throw new ArgumentOutOfRangeException(nameof(destinations), destinations.Length, "The number of destinations must be equal to the number of rendering threads!");
            }

            RoundedRectangle[] targets = targetSize.Split(destinations.Length);

            float zoomX = targetSize.Width / region.Width;
            float zoomY = targetSize.Height / region.Height;

            float zoom = (float)Math.Sqrt(zoomX * zoomY);

            Rectangle actualPageArea = new Rectangle(region.X0, region.Y0, region.X0 + targetSize.Width / zoom, region.Y0 + targetSize.Height / zoom);

            Rectangle[] origins = actualPageArea.Split(destinations.Length);

            //Make sure that each tile has the expected size in pixel, rounding errors notwithstanding.
            for (int i = 0; i < origins.Length; i++)
            {
                int countBlanks = 0;
                RoundedRectangle roundedOrigin = origins[i].Round(zoom);
                while (roundedOrigin.Width != targets[i].Width || roundedOrigin.Height != targets[i].Height)
                {
                    RoundedRectangle oldRoundedOrigin = roundedOrigin;

                    if (roundedOrigin.Width > targets[i].Width)
                    {
                        if (origins[i].X0 > actualPageArea.X0)
                        {
                            origins[i] = new Rectangle(origins[i].X0 + 0.5 / zoom, origins[i].Y0, origins[i].X1, origins[i].Y1);
                        }
                        else
                        {
                            origins[i] = new Rectangle(origins[i].X0, origins[i].Y0, origins[i].X1 - 0.5 / zoom, origins[i].Y1);
                        }
                    }
                    else if (roundedOrigin.Width < targets[i].Width)
                    {
                        if (origins[i].X1 < actualPageArea.X1)
                        {
                            origins[i] = new Rectangle(origins[i].X0, origins[i].Y0, origins[i].X1 + 0.5 / zoom, origins[i].Y1);
                        }
                        else
                        {
                            origins[i] = new Rectangle(origins[i].X0 - 0.5 / zoom, origins[i].Y0, origins[i].X1, origins[i].Y1);
                        }
                    }


                    if (roundedOrigin.Height > targets[i].Height)
                    {
                        if (origins[i].Y0 > actualPageArea.Y0)
                        {
                            origins[i] = new Rectangle(origins[i].X0, origins[i].Y0 + 0.5 / zoom, origins[i].X1, origins[i].Y1);
                        }
                        else
                        {
                            origins[i] = new Rectangle(origins[i].X0, origins[i].Y0, origins[i].X1, origins[i].Y1 - 0.5 / zoom);
                        }
                    }
                    else if (roundedOrigin.Height < targets[i].Height)
                    {
                        if (origins[i].X1 < actualPageArea.X1)
                        {
                            origins[i] = new Rectangle(origins[i].X0, origins[i].Y0, origins[i].X1, origins[i].Y1 + 0.5 / zoom);
                        }
                        else
                        {
                            origins[i] = new Rectangle(origins[i].X0, origins[i].Y0 - 0.5 / zoom, origins[i].X1, origins[i].Y1);
                        }
                    }

                    roundedOrigin = origins[i].Round(zoom);

                    if (roundedOrigin.Width == oldRoundedOrigin.Width && roundedOrigin.Height == oldRoundedOrigin.Height && (roundedOrigin.Width != targets[i].Width || roundedOrigin.Height != targets[i].Height))
                    {
                        countBlanks++;
                    }

                    if (countBlanks >= 100)
                    {
                        //It seems that we can't coerce the expected size and the actual size to be the same. Give up.
                        return;
                    }
                }
            }

            //Start each rendering thread.
            for (int i = 0; i < destinations.Length; i++)
            {
                double    dzoom  = zoom;
                Rectangle origin = origins[i];
                if (this.ImageXRes != 72 || this.ImageYRes != 72)
                {
                    dzoom *= Math.Sqrt(this.ImageXRes * this.ImageYRes) / 72;
                    origin = new Rectangle(origin.X0 * 72 / this.ImageXRes, origin.Y0 * 72 / this.ImageYRes, origin.X1 * 72 / this.ImageXRes, origin.Y1 * 72 / this.ImageYRes);
                }

                RenderingThreads[i].Render(Contexts[i].NativeContext, DisplayList, origin, (float)dzoom, destinations[i], pixelFormat, this.PageBounds, ClipToPageBounds);
            }

            //Wait until all the rendering threads have finished.
            for (int i = 0; i < destinations.Length; i++)
            {
                RenderingThreads[i].WaitForRendering();
            }
        }
Exemple #2
0
        /// <summary>
        /// Split the size into the specified number of <see cref="RoundedRectangle"/>s.
        /// </summary>
        /// <param name="divisions">The number of rectangles in which the size should be split. This must be factorisable using only powers of 2, 3, 5 or 7. Otherwise, the biggest number smaller than <paramref name="divisions"/> that satisfies this condition is used.</param>
        /// <returns>An array of <see cref="RoundedRectangle"/>s that when positioned properly cover an area of the size of this object.</returns>
        public     RoundedRectangle[] Split(int divisions)
        {
            divisions = Utils.GetAcceptableNumber(divisions);

            RoundedRectangle[] tbr = new RoundedRectangle[divisions];

            bool isVertical = this.Height > this.Width;

            if (divisions == 1)
            {
                tbr[0] = new RoundedRectangle(0, 0, Width, Height);
            }
            else if (divisions == 2)
            {
                if (isVertical)
                {
                    tbr[0] = new RoundedRectangle(0, 0, Width, Height / 2);
                    tbr[1] = new RoundedRectangle(0, Height / 2, Width, Height);
                }
                else
                {
                    tbr[0] = new RoundedRectangle(0, 0, Width / 2, Height);
                    tbr[1] = new RoundedRectangle(Width / 2, 0, Width, Height);
                }
            }
            else if (divisions == 3)
            {
                if (isVertical)
                {
                    tbr[0] = new RoundedRectangle(0, 0, Width / 2, 2 * Height / 3);
                    tbr[1] = new RoundedRectangle(Width / 2, 0, Width, 2 * Height / 3);
                    tbr[2] = new RoundedRectangle(0, 2 * Height / 3, Width, Height);
                }
                else
                {
                    tbr[0] = new RoundedRectangle(0, 0, 2 * Width / 3, Height / 2);
                    tbr[1] = new RoundedRectangle(0, Height / 2, 2 * Width / 3, Height);
                    tbr[2] = new RoundedRectangle(2 * Width / 3, 0, Width, Height);
                }
            }
            else if (divisions == 5)
            {
                if (isVertical)
                {
                    tbr[0] = new RoundedRectangle(0, 0, Width / 2, 2 * Height / 5);
                    tbr[1] = new RoundedRectangle(Width / 2, 0, Width, 2 * Height / 5);
                    tbr[2] = new RoundedRectangle(0, 2 * Height / 5, Width / 2, 4 * Height / 5);
                    tbr[3] = new RoundedRectangle(Width / 2, 2 * Height / 5, Width, 4 * Height / 5);
                    tbr[4] = new RoundedRectangle(0, 4 * Height / 5, Width, Height);
                }
                else
                {
                    tbr[0] = new RoundedRectangle(0, 0, 2 * Width / 5, Height / 2);
                    tbr[1] = new RoundedRectangle(0, Height / 2, 2 * Width / 5, Height);
                    tbr[2] = new RoundedRectangle(2 * Width / 5, 0, 4 * Width / 5, Height / 2);
                    tbr[3] = new RoundedRectangle(2 * Width / 5, Height / 2, 4 * Width / 5, Height);
                    tbr[4] = new RoundedRectangle(4 * Width / 5, 0, Width, Height);
                }
            }
            else if (divisions == 7)
            {
                if (isVertical)
                {
                    tbr[0] = new RoundedRectangle(0, 0, Width / 2, 2 * Height / 7);
                    tbr[1] = new RoundedRectangle(Width / 2, 0, Width, 2 * Height / 7);
                    tbr[2] = new RoundedRectangle(0, 2 * Height / 7, Width / 2, 4 * Height / 7);
                    tbr[3] = new RoundedRectangle(Width / 2, 2 * Height / 7, Width, 4 * Height / 7);
                    tbr[4] = new RoundedRectangle(0, 4 * Height / 7, Width / 2, 6 * Height / 7);
                    tbr[5] = new RoundedRectangle(Width / 2, 4 * Height / 7, Width, 6 * Height / 7);
                    tbr[6] = new RoundedRectangle(0, 6 * Height / 7, Width, Height);
                }
                else
                {
                    tbr[0] = new RoundedRectangle(0, 0, 2 * Width / 7, Height / 2);
                    tbr[1] = new RoundedRectangle(0, Height / 2, 2 * Width / 7, Height);
                    tbr[2] = new RoundedRectangle(2 * Width / 7, 0, 4 * Width / 7, Height / 2);
                    tbr[3] = new RoundedRectangle(2 * Width / 7, Height / 2, 4 * Width / 7, Height);
                    tbr[4] = new RoundedRectangle(4 * Width / 7, 0, 6 * Width / 7, Height / 2);
                    tbr[5] = new RoundedRectangle(4 * Width / 7, Height / 2, 6 * Width / 7, Height);
                    tbr[6] = new RoundedRectangle(6 * Width / 7, 0, Width, Height);
                }
            }
            else
            {
                for (int divisorInd = 0; divisorInd < Utils.AcceptableDivisors.Length; divisorInd++)
                {
                    if (divisions % Utils.AcceptableDivisors[divisorInd] == 0)
                    {
                        RoundedRectangle[] largerDivisions = this.Split(divisions / Utils.AcceptableDivisors[divisorInd]);

                        int pos = 0;

                        for (int i = 0; i < largerDivisions.Length; i++)
                        {
                            RoundedSize        s            = new RoundedSize(largerDivisions[i].Width, largerDivisions[i].Height);
                            RoundedRectangle[] currDivision = s.Split(Utils.AcceptableDivisors[divisorInd]);

                            for (int j = 0; j < currDivision.Length; j++)
                            {
                                tbr[pos] = new RoundedRectangle(largerDivisions[i].X0 + currDivision[j].X0, largerDivisions[i].Y0 + currDivision[j].Y0, largerDivisions[i].X0 + currDivision[j].X1, largerDivisions[i].Y0 + currDivision[j].Y1);
                                pos++;
                            }
                        }

                        break;
                    }
                }
            }

            return(tbr);
        }