Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
2 | pj | 1 | /* |
2 | * hybrid.c -- |
||
3 | * |
||
4 | * Procedures dealing with hybrid dithers. |
||
5 | * |
||
6 | */ |
||
7 | |||
8 | /* |
||
9 | * Copyright (c) 1995 The Regents of the University of California. |
||
10 | * All rights reserved. |
||
11 | * |
||
12 | * Permission to use, copy, modify, and distribute this software and its |
||
13 | * documentation for any purpose, without fee, and without written agreement is |
||
14 | * hereby granted, provided that the above copyright notice and the following |
||
15 | * two paragraphs appear in all copies of this software. |
||
16 | * |
||
17 | * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR |
||
18 | * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT |
||
19 | * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF |
||
20 | * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||
21 | * |
||
22 | * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, |
||
23 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY |
||
24 | * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS |
||
25 | * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO |
||
26 | * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. |
||
27 | */ |
||
28 | |||
29 | /* This file contains C code to implement an ordered dither. */ |
||
30 | |||
31 | #include "video.h" |
||
32 | #include "proto.h" |
||
33 | #include "dither.h" |
||
34 | |||
35 | #define DITH_SIZE 16 |
||
36 | |||
37 | |||
38 | /* Structures used to implement hybrid ordered dither/floyd-steinberg |
||
39 | dither algorithm. |
||
40 | */ |
||
41 | |||
42 | static unsigned char *l_darrays[DITH_SIZE]; |
||
43 | static unsigned char cr_fsarray[256][4]; |
||
44 | static unsigned char cb_fsarray[256][4]; |
||
45 | |||
46 | |||
47 | /* |
||
48 | *-------------------------------------------------------------- |
||
49 | * |
||
50 | * InitHybridDither-- |
||
51 | * |
||
52 | * Structures intialized for hybrid dithering. Ordered dither |
||
53 | * patterns set for luminance channel, f-s errors precomputed |
||
54 | * for chrominance channels. |
||
55 | * |
||
56 | * Results: |
||
57 | * None. |
||
58 | * |
||
59 | * Side effects: |
||
60 | * None. |
||
61 | * |
||
62 | *-------------------------------------------------------------- |
||
63 | */ |
||
64 | |||
65 | void |
||
66 | InitHybridDither() |
||
67 | { |
||
68 | int i, j, k, err_range, threshval; |
||
69 | unsigned char *lmark; |
||
70 | |||
71 | for (i=0; i<DITH_SIZE; i++) { |
||
72 | lmark = l_darrays[i] = (unsigned char *) malloc(256); |
||
73 | |||
74 | for (j=0; j<lum_values[0]; j++) { |
||
75 | *lmark++ = 0; |
||
76 | } |
||
77 | |||
78 | for (j=0; j<(LUM_RANGE-1); j++) { |
||
79 | err_range = lum_values[j+1] - lum_values[j]; |
||
80 | threshval = ((i * err_range) / DITH_SIZE)+lum_values[j]; |
||
81 | |||
82 | for (k=lum_values[j]; k<lum_values[j+1]; k++) { |
||
83 | if (k > threshval) *lmark++ = ((j+1) * (CR_RANGE * CB_RANGE)); |
||
84 | else *lmark++ = (j * (CR_RANGE * CB_RANGE)); |
||
85 | } |
||
86 | } |
||
87 | |||
88 | for (j=lum_values[LUM_RANGE-1]; j<256; j++) { |
||
89 | *lmark++ = (LUM_RANGE-1)*(CR_RANGE * CB_RANGE); |
||
90 | } |
||
91 | |||
92 | } |
||
93 | { |
||
94 | int cr1, cr2, cr3, cr4, err1, err2; |
||
95 | int cb1, cb2, cb3, cb4, val, nval; |
||
96 | |||
97 | for (i=0; i<256; i++) { |
||
98 | |||
99 | val = i; |
||
100 | |||
101 | cr1 = (val * CR_RANGE) / 256; |
||
102 | err1 = (val - cr_values[cr1])/2; |
||
103 | err2 = (val - cr_values[cr1]) - err1; |
||
104 | |||
105 | nval = val+err1; |
||
106 | if (nval > 255) nval = 255; |
||
107 | else if (nval < 0) nval = 0; |
||
108 | cr2 = (nval * CR_RANGE) / 256; |
||
109 | err1 = (nval - cr_values[cr2])/2; |
||
110 | |||
111 | nval = val+err2; |
||
112 | if (nval > 255) nval = 255; |
||
113 | else if (nval < 0) nval = 0; |
||
114 | cr3 = (nval * CR_RANGE) / 256; |
||
115 | err2 = (nval - cr_values[cr3])/2; |
||
116 | |||
117 | nval = val+err1+err2; |
||
118 | if (nval > 255) nval = 255; |
||
119 | else if (nval < 0) nval = 0; |
||
120 | cr4 = (nval * CR_RANGE) / 256; |
||
121 | |||
122 | cr_fsarray[i][0] = cr1*CB_RANGE; |
||
123 | cr_fsarray[i][1] = cr2*CB_RANGE; |
||
124 | cr_fsarray[i][2] = cr3*CB_RANGE; |
||
125 | cr_fsarray[i][3] = cr4*CB_RANGE; |
||
126 | } |
||
127 | |||
128 | for (i=0; i<256; i++) { |
||
129 | |||
130 | val = i; |
||
131 | |||
132 | cb1 = (val * CB_RANGE) / 256; |
||
133 | err1 = (val - cb_values[cb1])/2; |
||
134 | err2 = (val - cb_values[cb1]) - err1; |
||
135 | |||
136 | nval = val+err1; |
||
137 | if (nval > 255) nval = 255; |
||
138 | else if (nval < 0) nval = 0; |
||
139 | cb2 = (nval * CB_RANGE) / 256; |
||
140 | err1 = (nval - cb_values[cb2])/2; |
||
141 | |||
142 | nval = val+err2; |
||
143 | if (nval > 255) nval = 255; |
||
144 | else if (nval < 0) nval = 0; |
||
145 | cb3 = (nval * CB_RANGE) / 256; |
||
146 | err2 = (nval - cb_values[cb3])/2; |
||
147 | |||
148 | nval = val+err1+err2; |
||
149 | if (nval > 255) nval = 255; |
||
150 | else if (nval < 0) nval = 0; |
||
151 | cb4 = (nval * CB_RANGE) / 256; |
||
152 | |||
153 | cb_fsarray[i][0] = cb1; |
||
154 | cb_fsarray[i][1] = cb2; |
||
155 | cb_fsarray[i][2] = cb3; |
||
156 | cb_fsarray[i][3] = cb4; |
||
157 | } |
||
158 | } |
||
159 | } |
||
160 | |||
161 | /* |
||
162 | *-------------------------------------------------------------- |
||
163 | * |
||
164 | * HybridDitherImage -- |
||
165 | * |
||
166 | * Dithers an image using an ordered dither. |
||
167 | * Assumptions made: |
||
168 | * 1) The color space is allocated y:cr:cb = 8:4:4 |
||
169 | * 2) The spatial resolution of y:cr:cb is 4:1:1 |
||
170 | * The luminance channel is dithered based on the standard |
||
171 | * ordered dither pattern for a 4x4 area. The Chrominance |
||
172 | * channels are dithered based on precomputed f-s errors. |
||
173 | * Two errors are propogated per pixel. Errors are NOT propogated |
||
174 | * beyond a 2x2 pixel area. |
||
175 | * |
||
176 | * Results: |
||
177 | * None. |
||
178 | * |
||
179 | * Side effects: |
||
180 | * None. |
||
181 | * |
||
182 | *-------------------------------------------------------------- |
||
183 | */ |
||
184 | void |
||
185 | HybridDitherImage (lum, cr, cb, out, h, w) |
||
186 | unsigned char *lum; |
||
187 | unsigned char *cr; |
||
188 | unsigned char *cb; |
||
189 | unsigned char *out; |
||
190 | int w, h; |
||
191 | { |
||
192 | unsigned char *l, *r, *b, *o1, *o2; |
||
193 | unsigned char *l2; |
||
194 | int i, j; |
||
195 | |||
196 | l = lum; |
||
197 | l2 = lum+w; |
||
198 | r = cr; |
||
199 | b = cb; |
||
200 | o1 = out; |
||
201 | o2 = out+w; |
||
202 | |||
203 | for (i=0; i<h; i+=4) { |
||
204 | |||
205 | for (j=0; j<w; j+=4) { |
||
206 | |||
207 | *o1++ = pixel[(l_darrays[0][*l++] | cr_fsarray[*r][0] | cb_fsarray[*b][0])]; |
||
208 | *o1++ = pixel[(l_darrays[8][*l++] | cr_fsarray[*r][1] | cb_fsarray[*b][1])]; |
||
209 | *o2++ = pixel[(l_darrays[12][*l2++] | cr_fsarray[*r][2] | cb_fsarray[*b][2])]; |
||
210 | *o2++ = pixel[(l_darrays[4][*l2++] | cr_fsarray[*r++][3] | cb_fsarray[*b++][3])]; |
||
211 | |||
212 | *o1++ = pixel[(l_darrays[2][*l++] | cr_fsarray[*r][0] | cb_fsarray[*b][0])]; |
||
213 | *o1++ = pixel[(l_darrays[10][*l++] | cr_fsarray[*r][1] | cb_fsarray[*b][1])]; |
||
214 | *o2++ = pixel[(l_darrays[14][*l2++] | cr_fsarray[*r][2] | cb_fsarray[*b][2])]; |
||
215 | *o2++ = pixel[(l_darrays[6][*l2++] | cr_fsarray[*r++][3] | cb_fsarray[*b++][3])]; |
||
216 | } |
||
217 | |||
218 | l += w; l2 += w; |
||
219 | o1 += w; o2 += w; |
||
220 | |||
221 | for (j=0; j<w; j+=4) { |
||
222 | |||
223 | *o1++ = pixel[(l_darrays[3][*l++] | cr_fsarray[*r][1] | cb_fsarray[*b][1])]; |
||
224 | *o1++ = pixel[(l_darrays[11][*l++] | cr_fsarray[*r][0] | cb_fsarray[*b][0])]; |
||
225 | *o2++ = pixel[(l_darrays[15][*l2++] | cr_fsarray[*r][3] | cb_fsarray[*b][3])]; |
||
226 | *o2++ = pixel[(l_darrays[7][*l2++] | cr_fsarray[*r++][2] | cb_fsarray[*b++][2])]; |
||
227 | |||
228 | *o1++ = pixel[(l_darrays[1][*l++] | cr_fsarray[*r][1] | cb_fsarray[*b][1])]; |
||
229 | *o1++ = pixel[(l_darrays[9][*l++] | cr_fsarray[*r][0] | cb_fsarray[*b][0])]; |
||
230 | *o2++ = pixel[(l_darrays[13][*l2++] | cr_fsarray[*r][3] | cb_fsarray[*b][3])]; |
||
231 | *o2++ = pixel[(l_darrays[5][*l2++] | cr_fsarray[*r++][2] | cb_fsarray[*b++][2])]; |
||
232 | } |
||
233 | |||
234 | l += w; l2 += w; |
||
235 | o1 += w; o2 += w; |
||
236 | } |
||
237 | } |
||
238 | |||
239 | |||
240 |