sinc with TL rev. 38618.
[luatex.git] / source / libs / poppler / poppler-0.37.0 / splash / SplashScreen.cc
blob68ccd7ddda06edc0a59c847b276aa1be6c81f84e
1 //========================================================================
2 //
3 // SplashScreen.cc
4 //
5 //========================================================================
7 //========================================================================
8 //
9 // Modified under the Poppler project - http://poppler.freedesktop.org
11 // All changes made under the Poppler project to this file are licensed
12 // under GPL version 2 or later
14 // Copyright (C) 2009 Albert Astals Cid <aacid@kde.org>
15 // Copyright (C) 2012 Fabio D'Urso <fabiodurso@hotmail.it>
17 // To see a description of the changes please see the Changelog file that
18 // came with your tarball or type make ChangeLog if you are building from git
20 //========================================================================
22 #include <config.h>
24 #ifdef USE_GCC_PRAGMAS
25 #pragma implementation
26 #endif
28 #include <stdlib.h>
29 #include <string.h>
30 #include <algorithm>
31 #include "goo/gmem.h"
32 #include "goo/grandom.h"
33 #include "SplashMath.h"
34 #include "SplashScreen.h"
36 static SplashScreenParams defaultParams = {
37 splashScreenDispersed, // type
38 2, // size
39 2, // dotRadius
40 1.0, // gamma
41 0.0, // blackThreshold
42 1.0 // whiteThreshold
45 //------------------------------------------------------------------------
47 struct SplashScreenPoint {
48 int x, y;
49 int dist;
53 struct cmpDistancesFunctor {
54 bool operator()(const SplashScreenPoint &p0, const SplashScreenPoint &p1) {
55 return p0.dist < p1.dist;
59 //------------------------------------------------------------------------
60 // SplashScreen
61 //------------------------------------------------------------------------
63 // If <clustered> is true, this generates a 45 degree screen using a
64 // circular dot spot function. DPI = resolution / ((size / 2) *
65 // sqrt(2)). If <clustered> is false, this generates an optimal
66 // threshold matrix using recursive tesselation. Gamma correction
67 // (gamma = 1 / 1.33) is also computed here.
68 SplashScreen::SplashScreen(SplashScreenParams *params) {
70 if (!params) {
71 params = &defaultParams;
74 screenParams = params;
75 mat = NULL;
76 size = 0;
77 maxVal = 0;
78 minVal = 0;
81 void SplashScreen::createMatrix()
83 Guchar u;
84 int black, white, i;
86 SplashScreenParams *params = screenParams;
88 // size must be a power of 2, and at least 2
89 for (size = 2, log2Size = 1; size < params->size; size <<= 1, ++log2Size) ;
91 switch (params->type) {
93 case splashScreenDispersed:
94 mat = (Guchar *)gmallocn(size * size, sizeof(Guchar));
95 buildDispersedMatrix(size/2, size/2, 1, size/2, 1);
96 break;
98 case splashScreenClustered:
99 mat = (Guchar *)gmallocn(size * size, sizeof(Guchar));
100 buildClusteredMatrix();
101 break;
103 case splashScreenStochasticClustered:
104 // size must be at least 2*r
105 while (size < (params->dotRadius << 1)) {
106 size <<= 1;
107 ++log2Size;
109 mat = (Guchar *)gmallocn(size * size, sizeof(Guchar));
110 buildSCDMatrix(params->dotRadius);
111 break;
114 sizeM1 = size - 1;
116 // do gamma correction and compute minVal/maxVal
117 minVal = 255;
118 maxVal = 0;
119 black = splashRound((SplashCoord)255.0 * params->blackThreshold);
120 if (black < 1) {
121 black = 1;
123 int whiteAux = splashRound((SplashCoord)255.0 * params->whiteThreshold);
124 if (whiteAux > 255) {
125 white = 255;
126 } else {
127 white = whiteAux;
129 for (i = 0; i < size * size; ++i) {
130 u = splashRound((SplashCoord)255.0 *
131 splashPow((SplashCoord)mat[i] / 255.0, params->gamma));
132 if (u < black) {
133 u = (Guchar)black;
134 } else if (u >= white) {
135 u = (Guchar)white;
137 mat[i] = u;
138 if (u < minVal) {
139 minVal = u;
140 } else if (u > maxVal) {
141 maxVal = u;
146 void SplashScreen::buildDispersedMatrix(int i, int j, int val,
147 int delta, int offset) {
148 if (delta == 0) {
149 // map values in [1, size^2] --> [1, 255]
150 mat[(i << log2Size) + j] = 1 + (254 * (val - 1)) / (size * size - 1);
151 } else {
152 buildDispersedMatrix(i, j,
153 val, delta / 2, 4*offset);
154 buildDispersedMatrix((i + delta) % size, (j + delta) % size,
155 val + offset, delta / 2, 4*offset);
156 buildDispersedMatrix((i + delta) % size, j,
157 val + 2*offset, delta / 2, 4*offset);
158 buildDispersedMatrix((i + 2*delta) % size, (j + delta) % size,
159 val + 3*offset, delta / 2, 4*offset);
163 void SplashScreen::buildClusteredMatrix() {
164 SplashCoord *dist;
165 SplashCoord u, v, d;
166 Guchar val;
167 int size2, x, y, x1, y1, i;
169 size2 = size >> 1;
171 // initialize the threshold matrix
172 for (y = 0; y < size; ++y) {
173 for (x = 0; x < size; ++x) {
174 mat[(y << log2Size) + x] = 0;
178 // build the distance matrix
179 dist = (SplashCoord *)gmallocn(size * size2, sizeof(SplashCoord));
180 for (y = 0; y < size2; ++y) {
181 for (x = 0; x < size2; ++x) {
182 if (x + y < size2 - 1) {
183 u = (SplashCoord)x + 0.5 - 0;
184 v = (SplashCoord)y + 0.5 - 0;
185 } else {
186 u = (SplashCoord)x + 0.5 - (SplashCoord)size2;
187 v = (SplashCoord)y + 0.5 - (SplashCoord)size2;
189 dist[y * size2 + x] = u*u + v*v;
192 for (y = 0; y < size2; ++y) {
193 for (x = 0; x < size2; ++x) {
194 if (x < y) {
195 u = (SplashCoord)x + 0.5 - 0;
196 v = (SplashCoord)y + 0.5 - (SplashCoord)size2;
197 } else {
198 u = (SplashCoord)x + 0.5 - (SplashCoord)size2;
199 v = (SplashCoord)y + 0.5 - 0;
201 dist[(size2 + y) * size2 + x] = u*u + v*v;
205 // build the threshold matrix
206 x1 = y1 = 0; // make gcc happy
207 for (i = 0; i < size * size2; ++i) {
208 d = -1;
209 for (y = 0; y < size; ++y) {
210 for (x = 0; x < size2; ++x) {
211 if (mat[(y << log2Size) + x] == 0 &&
212 dist[y * size2 + x] > d) {
213 x1 = x;
214 y1 = y;
215 d = dist[y1 * size2 + x1];
219 // map values in [0, 2*size*size2-1] --> [1, 255]
220 val = 1 + (254 * (2*i)) / (2*size*size2 - 1);
221 mat[(y1 << log2Size) + x1] = val;
222 val = 1 + (254 * (2*i+1)) / (2*size*size2 - 1);
223 if (y1 < size2) {
224 mat[((y1 + size2) << log2Size) + x1 + size2] = val;
225 } else {
226 mat[((y1 - size2) << log2Size) + x1 + size2] = val;
230 gfree(dist);
233 // Compute the distance between two points on a toroid.
234 int SplashScreen::distance(int x0, int y0, int x1, int y1) {
235 int dx0, dx1, dx, dy0, dy1, dy;
237 dx0 = abs(x0 - x1);
238 dx1 = size - dx0;
239 dx = dx0 < dx1 ? dx0 : dx1;
240 dy0 = abs(y0 - y1);
241 dy1 = size - dy0;
242 dy = dy0 < dy1 ? dy0 : dy1;
243 return dx * dx + dy * dy;
246 // Algorithm taken from:
247 // Victor Ostromoukhov and Roger D. Hersch, "Stochastic Clustered-Dot
248 // Dithering" in Color Imaging: Device-Independent Color, Color
249 // Hardcopy, and Graphic Arts IV, SPIE Vol. 3648, pp. 496-505, 1999.
250 void SplashScreen::buildSCDMatrix(int r) {
251 SplashScreenPoint *dots, *pts;
252 int dotsLen, dotsSize;
253 char *tmpl;
254 char *grid;
255 int *region, *dist;
256 int x, y, xx, yy, x0, x1, y0, y1, i, j, d, iMin, dMin, n;
258 // generate the random space-filling curve
259 pts = (SplashScreenPoint *)gmallocn(size * size, sizeof(SplashScreenPoint));
260 i = 0;
261 for (y = 0; y < size; ++y) {
262 for (x = 0; x < size; ++x) {
263 pts[i].x = x;
264 pts[i].y = y;
265 ++i;
268 for (i = 0; i < size * size; ++i) {
269 j = i + (int)((double)(size * size - i) * grandom_double());
270 x = pts[i].x;
271 y = pts[i].y;
272 pts[i].x = pts[j].x;
273 pts[i].y = pts[j].y;
274 pts[j].x = x;
275 pts[j].y = y;
278 // construct the circle template
279 tmpl = (char *)gmallocn((r+1)*(r+1), sizeof(char));
280 for (y = 0; y <= r; ++y) {
281 for (x = 0; x <= r; ++x) {
282 tmpl[y*(r+1) + x] = (x * y <= r * r) ? 1 : 0;
286 // mark all grid cells as free
287 grid = (char *)gmallocn(size * size, sizeof(char));
288 for (y = 0; y < size; ++y) {
289 for (x = 0; x < size; ++x) {
290 grid[(y << log2Size) + x] = 0;
294 // walk the space-filling curve, adding dots
295 dotsLen = 0;
296 dotsSize = 32;
297 dots = (SplashScreenPoint *)gmallocn(dotsSize, sizeof(SplashScreenPoint));
298 for (i = 0; i < size * size; ++i) {
299 x = pts[i].x;
300 y = pts[i].y;
301 if (!grid[(y << log2Size) + x]) {
302 if (dotsLen == dotsSize) {
303 dotsSize *= 2;
304 dots = (SplashScreenPoint *)greallocn(dots, dotsSize,
305 sizeof(SplashScreenPoint));
307 dots[dotsLen++] = pts[i];
308 for (yy = 0; yy <= r; ++yy) {
309 y0 = (y + yy) % size;
310 y1 = (y - yy + size) % size;
311 for (xx = 0; xx <= r; ++xx) {
312 if (tmpl[yy*(r+1) + xx]) {
313 x0 = (x + xx) % size;
314 x1 = (x - xx + size) % size;
315 grid[(y0 << log2Size) + x0] = 1;
316 grid[(y0 << log2Size) + x1] = 1;
317 grid[(y1 << log2Size) + x0] = 1;
318 grid[(y1 << log2Size) + x1] = 1;
325 gfree(tmpl);
326 gfree(grid);
328 // assign each cell to a dot, compute distance to center of dot
329 region = (int *)gmallocn(size * size, sizeof(int));
330 dist = (int *)gmallocn(size * size, sizeof(int));
331 for (y = 0; y < size; ++y) {
332 for (x = 0; x < size; ++x) {
333 iMin = 0;
334 dMin = distance(dots[0].x, dots[0].y, x, y);
335 for (i = 1; i < dotsLen; ++i) {
336 d = distance(dots[i].x, dots[i].y, x, y);
337 if (d < dMin) {
338 iMin = i;
339 dMin = d;
342 region[(y << log2Size) + x] = iMin;
343 dist[(y << log2Size) + x] = dMin;
347 // compute threshold values
348 for (i = 0; i < dotsLen; ++i) {
349 n = 0;
350 for (y = 0; y < size; ++y) {
351 for (x = 0; x < size; ++x) {
352 if (region[(y << log2Size) + x] == i) {
353 pts[n].x = x;
354 pts[n].y = y;
355 pts[n].dist = distance(dots[i].x, dots[i].y, x, y);
356 ++n;
360 std::sort(pts, pts + n, cmpDistancesFunctor());
361 for (j = 0; j < n; ++j) {
362 // map values in [0 .. n-1] --> [255 .. 1]
363 mat[(pts[j].y << log2Size) + pts[j].x] = 255 - (254 * j) / (n - 1);
367 gfree(pts);
368 gfree(region);
369 gfree(dist);
371 gfree(dots);
374 SplashScreen::SplashScreen(SplashScreen *screen) {
375 screenParams = screen->screenParams;
376 size = screen->size;
377 sizeM1 = screen->sizeM1;
378 log2Size = screen->log2Size;
379 mat = (Guchar *)gmallocn(size * size, sizeof(Guchar));
380 memcpy(mat, screen->mat, size * size * sizeof(Guchar));
381 minVal = screen->minVal;
382 maxVal = screen->maxVal;
385 SplashScreen::~SplashScreen() {
386 gfree(mat);