1 //========================================================================
5 //========================================================================
7 //========================================================================
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 //========================================================================
24 #ifdef USE_GCC_PRAGMAS
25 #pragma implementation
32 #include "goo/grandom.h"
33 #include "SplashMath.h"
34 #include "SplashScreen.h"
36 static SplashScreenParams defaultParams
= {
37 splashScreenDispersed
, // type
41 0.0, // blackThreshold
45 //------------------------------------------------------------------------
47 struct SplashScreenPoint
{
53 struct cmpDistancesFunctor
{
54 bool operator()(const SplashScreenPoint
&p0
, const SplashScreenPoint
&p1
) {
55 return p0
.dist
< p1
.dist
;
59 //------------------------------------------------------------------------
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
) {
71 params
= &defaultParams
;
74 screenParams
= params
;
81 void SplashScreen::createMatrix()
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);
98 case splashScreenClustered
:
99 mat
= (Guchar
*)gmallocn(size
* size
, sizeof(Guchar
));
100 buildClusteredMatrix();
103 case splashScreenStochasticClustered
:
104 // size must be at least 2*r
105 while (size
< (params
->dotRadius
<< 1)) {
109 mat
= (Guchar
*)gmallocn(size
* size
, sizeof(Guchar
));
110 buildSCDMatrix(params
->dotRadius
);
116 // do gamma correction and compute minVal/maxVal
119 black
= splashRound((SplashCoord
)255.0 * params
->blackThreshold
);
123 int whiteAux
= splashRound((SplashCoord
)255.0 * params
->whiteThreshold
);
124 if (whiteAux
> 255) {
129 for (i
= 0; i
< size
* size
; ++i
) {
130 u
= splashRound((SplashCoord
)255.0 *
131 splashPow((SplashCoord
)mat
[i
] / 255.0, params
->gamma
));
134 } else if (u
>= white
) {
140 } else if (u
> maxVal
) {
146 void SplashScreen::buildDispersedMatrix(int i
, int j
, int val
,
147 int delta
, int offset
) {
149 // map values in [1, size^2] --> [1, 255]
150 mat
[(i
<< log2Size
) + j
] = 1 + (254 * (val
- 1)) / (size
* size
- 1);
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() {
167 int size2
, x
, y
, x1
, y1
, i
;
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;
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
) {
195 u
= (SplashCoord
)x
+ 0.5 - 0;
196 v
= (SplashCoord
)y
+ 0.5 - (SplashCoord
)size2
;
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
) {
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
) {
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);
224 mat
[((y1
+ size2
) << log2Size
) + x1
+ size2
] = val
;
226 mat
[((y1
- size2
) << log2Size
) + x1
+ size2
] = val
;
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
;
239 dx
= dx0
< dx1
? dx0
: dx1
;
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
;
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
));
261 for (y
= 0; y
< size
; ++y
) {
262 for (x
= 0; x
< size
; ++x
) {
268 for (i
= 0; i
< size
* size
; ++i
) {
269 j
= i
+ (int)((double)(size
* size
- i
) * grandom_double());
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
297 dots
= (SplashScreenPoint
*)gmallocn(dotsSize
, sizeof(SplashScreenPoint
));
298 for (i
= 0; i
< size
* size
; ++i
) {
301 if (!grid
[(y
<< log2Size
) + x
]) {
302 if (dotsLen
== dotsSize
) {
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;
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
) {
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
);
342 region
[(y
<< log2Size
) + x
] = iMin
;
343 dist
[(y
<< log2Size
) + x
] = dMin
;
347 // compute threshold values
348 for (i
= 0; i
< dotsLen
; ++i
) {
350 for (y
= 0; y
< size
; ++y
) {
351 for (x
= 0; x
< size
; ++x
) {
352 if (region
[(y
<< log2Size
) + x
] == i
) {
355 pts
[n
].dist
= distance(dots
[i
].x
, dots
[i
].y
, x
, y
);
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);
374 SplashScreen::SplashScreen(SplashScreen
*screen
) {
375 screenParams
= screen
->screenParams
;
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() {