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
61typedef 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