1 /*
2  * Copyright (c) 1996, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 /*
27  * This file contains macro definitions for the Encoding category of
28  * the macros used by the generic scaleloop function.
29  *
30  * This implementation uses a Floyd-Steinberg error diffusion technique
31  * to produce a very high quality version of an image with only an 8-bit
32  * (or less) gray ramp.  The error diffusion technique requires that the
33  * input color information be delivered in a special order from the top
34  * row to the bottom row and then left to right within each row, thus
35  * it is only valid in cases where the ImageProducer has specified the
36  * TopDownLeftRight delivery hint.  If the data is not read in that order,
37  * no mathematical or memory access errors should occur, but the dithering
38  * error will be spread through the pixels of the output image in an
39  * unpleasant manner.
40  */
41 
42 #include "img_fsutil.h"
43 
44 /*
45  * These definitions vector the standard macro names to the "Gray"
46  * versions of those macros only if the "DitherDeclared" keyword has
47  * not yet been defined elsewhere.  The "DitherDeclared" keyword is
48  * also defined here to claim ownership of the primary implementation
49  * even though this file does not rely on the definitions in any other
50  * files.
51  */
52 #ifndef DitherDeclared
53 #define DitherDeclared
54 #define DeclareDitherVars       DeclareGrayDitherVars
55 #define InitDither              InitGrayDither
56 #define StartDitherLine         StartGrayDitherLine
57 #define DitherPixel             GrayDitherPixel
58 #define DitherBufComplete       GrayDitherBufComplete
59 #endif
60 
61 typedef struct {
62     int gray;
63 } GrayDitherError;
64 
65 #define DeclareGrayDitherVars                                   \
66     extern unsigned char img_grays[256];                        \
67     extern unsigned char img_bwgamma[256];                      \
68     int egray;                                                  \
69     GrayDitherError *gep;
70 
71 #define InitGrayDither(cvdata, clrdata, dstTW)                          \
72     do {                                                                \
73         if (cvdata->fserrors == 0) {                                    \
74             int size = (dstTW + 2) * sizeof(GrayDitherError);           \
75             gep = (GrayDitherError *) sysMalloc(size);                  \
76             if (gep == 0) {                                             \
77                 SignalError(0, JAVAPKG "OutOfMemoryError", 0);          \
78                 return SCALEFAILURE;                                    \
79             }                                                           \
80             memset(gep, 0, size);                                       \
81             cvdata->fserrors = (void *) gep;                            \
82         }                                                               \
83     } while (0)
84 
85 
86 #define StartGrayDitherLine(cvdata, dstX1, dstY)                        \
87     do {                                                                \
88         gep = cvdata->fserrors;                                         \
89         if (dstX1) {                                                    \
90             egray = gep[0].gray;                                        \
91             gep += dstX1;                                               \
92         } else {                                                        \
93             egray = 0;                                                  \
94         }                                                               \
95     } while (0)
96 
97 #define GrayDitherPixel(dstX, dstY, pixel, red, green, blue)            \
98     do {                                                                \
99         int e1, e2, e3;                                                 \
100                                                                         \
101         /* convert to gray value */                                     \
102         e2 = RGBTOGRAY(red, green, blue);                               \
103                                                                         \
104         /* add previous errors */                                       \
105         e2 += gep[1].gray;                                              \
106                                                                         \
107         /* bounds checking */                                           \
108         e2 = ComponentBound(e2);                                        \
109                                                                         \
110         /* Store the closest color in the destination pixel */          \
111         e2 = img_bwgamma[e2];                                           \
112         pixel = img_grays[e2];                                          \
113         GetPixelRGB(pixel, red, green, blue);                           \
114                                                                         \
115         /* Set the error from the previous lap */                       \
116         gep[1].gray = egray;                                            \
117                                                                         \
118         /* compute the errors */                                        \
119         egray = e2 - red;                                               \
120                                                                         \
121         /* distribute the errors */                                     \
122         DitherDist(gep, e1, e2, e3, egray, gray);                       \
123         gep++;                                                          \
124     } while (0)
125 
126 #define GrayDitherBufComplete(cvdata, dstX1)                            \
127     do {                                                                \
128         if (dstX1) {                                                    \
129             gep = cvdata->fserrors;                                     \
130             gep[0].gray = egray;                                        \
131         }                                                               \
132     } while (0)
133