MuPDFCore 1.8.0
Multiplatform .NET bindings for MuPDF
Loading...
Searching...
No Matches
Utils.cs
1/*
2 MuPDFCore - A set of multiplatform .NET Core bindings for MuPDF.
3 Copyright (C) 2020 Giorgio Bianchini
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Affero General Public License as
7 published by the Free Software Foundation, version 3.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU Affero General Public License for more details.
13
14 You should have received a copy of the GNU Affero General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>
16*/
17
18using System;
19
20namespace MuPDFCore
21{
22 /// <summary>
23 /// Contains useful methods.
24 /// </summary>
25 internal static class Utils
26 {
27 /// <summary>
28 /// The factors by which we can divide a rectangle/size.
29 /// </summary>
30 public static readonly int[] AcceptableDivisors = new[] { 2, 3, 5, 7 };
31
32 /// <summary>
33 /// Computes the biggest number smaller than or equal to the specified value that is factorisable using only the <see cref="AcceptableDivisors"/>.
34 /// </summary>
35 /// <param name="n">The maximum number.</param>
36 /// <returns>A number that is &lt;= <paramref name="n"/> and is factorisable using only the <see cref="AcceptableDivisors"/>.</returns>
37 public static int GetAcceptableNumber(int n)
38 {
39 for (int i = n; i >= 1; i--)
40 {
41 if (IsAcceptableNumber(i))
42 {
43 return i;
44 }
45 }
46
47 throw new ArgumentOutOfRangeException(nameof(n), n, "The number must be strictly higher than 0!");
48 }
49
50 /// <summary>
51 /// Determine whether a number is factorisable using only the <see cref="AcceptableDivisors"/>.
52 /// </summary>
53 /// <param name="n">The number to analyse.</param>
54 /// <returns>A boolean value indicating whether the number is factorisable using only the <see cref="AcceptableDivisors"/>.</returns>
55 public static bool IsAcceptableNumber(int n)
56 {
57 if (n == 0)
58 {
59 return false;
60 }
61 else if (n == 1)
62 {
63 return true;
64 }
65 else
66 {
67 for (int i = 0; i < AcceptableDivisors.Length; i++)
68 {
69 bool divided = false;
70
71 while (n % AcceptableDivisors[i] == 0)
72 {
73 n /= AcceptableDivisors[i];
74 divided = true;
75 }
76
77 if (divided)
78 {
79 return IsAcceptableNumber(n);
80 }
81 }
82
83 return false;
84 }
85 }
86
87 /// <summary>
88 /// Clear all pixels outside of a specified region.
89 /// </summary>
90 /// <param name="image">A pointer to the address where the pixel data is stored.</param>
91 /// <param name="imageSize">The size in pixels of the image.</param>
92 /// <param name="imageArea">The area represented by the image.</param>
93 /// <param name="clipArea">The region outside which all pixels will be cleared, in image units.</param>
94 /// <param name="pixelFormat">The format of the pixel data.</param>
95 public static void ClipImage(IntPtr image, RoundedSize imageSize, Rectangle imageArea, Rectangle clipArea, PixelFormats pixelFormat)
96 {
97 int clipLeft = Math.Max(0, (int)Math.Ceiling((clipArea.X0 - imageArea.X0) / imageArea.Width * imageSize.Width - 0.001));
98 int clipRight = Math.Max(0, (int)Math.Floor(imageSize.Width - (imageArea.X1 - clipArea.X1) / imageArea.Width * imageSize.Width + 0.001));
99
100 int clipTop = Math.Max(0, (int)Math.Ceiling((clipArea.Y0 - imageArea.Y0) / imageArea.Height * imageSize.Height - 0.001));
101 int clipBottom = Math.Max(0, (int)Math.Floor(imageSize.Height - (imageArea.Y1 - clipArea.Y1) / imageArea.Height * imageSize.Height + 0.001));
102
103 int pixelSize = -1;
104 byte clearValue = 0;
105
106 switch (pixelFormat)
107 {
108 case PixelFormats.RGB:
109 case PixelFormats.BGR:
110 pixelSize = 3;
111 clearValue = 255;
112 break;
113 case PixelFormats.RGBA:
114 case PixelFormats.BGRA:
115 pixelSize = 4;
116 clearValue = 0;
117 break;
118 }
119
120 int stride = imageSize.Width * pixelSize;
121
122 if (clipLeft > 0 || clipRight < imageSize.Width || clipTop > 0 || clipBottom < imageSize.Height)
123 {
124 unsafe
125 {
126 byte* imageData = (byte*)image;
127
128 for (int y = 0; y < imageSize.Height; y++)
129 {
130 if (y < clipTop || y >= clipBottom)
131 {
132 for (int x = 0; x < imageSize.Width; x++)
133 {
134 for (int i = 0; i < pixelSize; i++)
135 {
136 imageData[y * stride + x * pixelSize + i] = clearValue;
137 }
138 }
139 }
140 else
141 {
142 for (int x = 0; x < Math.Min(clipLeft, imageSize.Width); x++)
143 {
144 for (int i = 0; i < pixelSize; i++)
145 {
146 imageData[y * stride + x * pixelSize + i] = clearValue;
147 }
148 }
149
150 for (int x = Math.Max(0, clipRight); x < imageSize.Width; x++)
151 {
152 for (int i = 0; i < pixelSize; i++)
153 {
154 imageData[y * stride + x * pixelSize + i] = clearValue;
155 }
156 }
157 }
158 }
159 }
160 }
161 }
162
163 /// <summary>
164 /// Converts an image with premultiplied alpha values into an image with unpremultiplied alpha values.
165 /// </summary>
166 /// <param name="image">A pointer to the address where the pixel data is stored.</param>
167 /// <param name="imageSize">The size in pixels of the image.</param>
168 public static void UnpremultiplyAlpha(IntPtr image, RoundedSize imageSize)
169 {
170 int stride = imageSize.Width * 4;
171
172 unsafe
173 {
174 byte* imageData = (byte*)image;
175
176 for (int y = 0; y < imageSize.Height; y++)
177 {
178 for (int x = 0; x < imageSize.Width; x++)
179 {
180 if (imageData[y * stride + x * 4 + 3] > 0)
181 {
182 imageData[y * stride + x * 4] = (byte)(imageData[y * stride + x * 4] * 255 / imageData[y * stride + x * 4 + 3]);
183 imageData[y * stride + x * 4 + 1] = (byte)(imageData[y * stride + x * 4 + 1] * 255 / imageData[y * stride + x * 4 + 3]);
184 imageData[y * stride + x * 4 + 2] = (byte)(imageData[y * stride + x * 4 + 2] * 255 / imageData[y * stride + x * 4 + 3]);
185 }
186 }
187 }
188 }
189 }
190 }
191}
PixelFormats
Pixel formats supported by the library.
Definition: MuPDF.cs:251