Subversion Repositories shark

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 pj 1
/*
2
 * fs2.c --
3
 *
4
 *      Procedures dealing with Floyd-Steinberg dithering with 2 error
5
 *      values propagated.
6
 *
7
 */
8
 
9
/*
10
 * Copyright (c) 1995 The Regents of the University of California.
11
 * All rights reserved.
12
 *
13
 * Permission to use, copy, modify, and distribute this software and its
14
 * documentation for any purpose, without fee, and without written agreement is
15
 * hereby granted, provided that the above copyright notice and the following
16
 * two paragraphs appear in all copies of this software.
17
 *
18
 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
19
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
20
 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
21
 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
22
 *
23
 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
24
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
25
 * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
26
 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
27
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
28
 */
29
 
30
#include "video.h"
31
#include "dither.h"
32
#include "fs2.h"
33
#include "proto.h"
34
#ifdef __STDC__
35
#include <stdlib.h>
36
#else
37
#include <malloc.h>     /* member of stdlib.h included in header.h */
38
#endif
39
 
40
/* Structures for precomputed error propogation values. */
41
 
42
static FS2DithVal lum_index[256];
43
static FS2DithVal cr_index[256];
44
static FS2DithVal cb_index[256];
45
 
46
 
47
 
48
/*
49
 *--------------------------------------------------------------
50
 *
51
 * InitFS2Dither --
52
 *
53
 *      Initializes structures for precomputed 2 error f-s dithering.
54
 *      The value field of the structure contains the pixel component
55
 *      of the particular channel in question. Thus the addition of
56
 *      the value field of a structure in the luminance index, a
57
 *      structure in the Cr index, and a structure in the Cb index will
58
 *      yeild a color number. This color number can then be transformed
59
 *      into a pixel value to be displayed. Each channel can then be
60
 *      processed (i.e. dithered) separately, with the results being
61
 *      added up and remapped to yield a final pixel value.
62
 *
63
 * Results:
64
 *      None.
65
 *
66
 * Side effects:
67
 *      None.
68
 *
69
 *--------------------------------------------------------------
70
 */
71
 
72
void InitFS2Dither()
73
{
74
  int i;
75
 
76
  /* For each possible pixel value, precompute propogated error and
77
     store in array.
78
  */
79
 
80
  for (i=0; i<256; i++) {
81
    lum_index[i].value = (i * LUM_RANGE) / 256;
82
 
83
    lum_index[i].e1 = (i-lum_values[lum_index[i].value]) / 2;
84
    lum_index[i].e3 = (i - lum_values[lum_index[i].value]) - lum_index[i].e1;
85
 
86
    lum_index[i].value *= LUM_BASE;
87
 
88
    cr_index[i].value = (i * CR_RANGE) / 256;
89
 
90
    cr_index[i].e1 = (i - cr_values[cr_index[i].value]) / 2;
91
    cr_index[i].e3 = (i - cr_values[cr_index[i].value]) - cr_index[i].e1 ;
92
 
93
    cr_index[i].value *= CR_BASE;
94
 
95
    cb_index[i].value = (i * CB_RANGE) / 256;
96
 
97
    cb_index[i].e1 = (i - cb_values[cb_index[i].value]) / 2;
98
    cb_index[i].e3 = (i - cb_values[cb_index[i].value]) - cb_index[i].e1;
99
 
100
    cb_index[i].value *= CB_BASE;
101
 
102
  }
103
 
104
}
105
 
106
 
107
/*
108
 *--------------------------------------------------------------
109
 *
110
 * DitherImage --
111
 *
112
 *      Converts lum, cr, cb image planes into fixed colormap
113
 *      space.
114
 *
115
 * Results:
116
 *      the display plane is replaced by 8-bit colormap space
117
 *      image.
118
 *
119
 * Side effects:
120
 *      Hopefully, none.
121
 *
122
 *--------------------------------------------------------------
123
 */
124
 
125
void FS2DitherImage(lum, cr, cb, disp, rows, cols)
126
     unsigned char *lum, *cr, *cb, *disp;
127
     int rows, cols;
128
{
129
  static char *cur_row_error, *next_row_error;
130
  static int first = 1;
131
  char  *cur_row_err_mark, *next_row_err_mark;
132
  char *temp;
133
  int i, j, pixsum, c_cols;
134
  unsigned char *cur_row, *channel, *dest_row;
135
  FS2DithVal *chan_index;
136
 
137
  /* Allocate error arrays. */
138
 
139
  if (first) {
140
    cur_row_error = (char *) malloc((unsigned int) cols+2);
141
    next_row_error = (char *) malloc((unsigned int) cols+2);
142
    first = 0;
143
  }
144
 
145
  /* Initialize error arrays. */
146
 
147
  memset(cur_row_error, 0, cols+2);
148
  memset(next_row_error, 0, cols+2);
149
 
150
  /* Use luminance values first. */
151
 
152
  /* For each two rows, do... */
153
 
154
  for(i=0; i<rows; i+=2) {
155
 
156
    /* Establish pointer to current source and destination rows. */
157
    cur_row = lum + (i*cols);
158
    dest_row = disp + (i*cols);
159
 
160
    /* Establish pointers to error arrays. */
161
    cur_row_err_mark = cur_row_error + 1;
162
    next_row_err_mark = next_row_error + 1;
163
 
164
 
165
    /* For each column within first row do... */
166
 
167
    for (j=0; j<cols; j++) {
168
 
169
      /* Calculate pixel value with error. */
170
 
171
      pixsum = *cur_row + *cur_row_err_mark;
172
 
173
      /* Bounds check. */
174
      if (pixsum < 0) pixsum = 0;
175
      else if (pixsum > 255) pixsum = 255;
176
 
177
      /* Establish dest value, propogate errors. */
178
 
179
      *dest_row = lum_index[pixsum].value;
180
      *(cur_row_err_mark+1) += lum_index[pixsum].e1;
181
      *next_row_err_mark += lum_index[pixsum].e3;
182
 
183
      /* Advance pointers. */
184
 
185
      cur_row++;
186
      dest_row++;
187
      cur_row_err_mark++;
188
      next_row_err_mark++;
189
    }
190
 
191
    /* Switch error arrays, so next row errors are now current row errors, and
192
       vice versa.
193
    */
194
 
195
    temp = cur_row_error;
196
    cur_row_error = next_row_error;
197
    next_row_error = temp;
198
 
199
    /* Reset next row errors. */
200
 
201
    memset(next_row_error, 0, cols+2);
202
 
203
    /* Establish pointers for second row. This one will be processed right to
204
       left to establish serpantine motion.
205
    */
206
 
207
    cur_row += cols-1;
208
    dest_row += cols-1;
209
    cur_row_err_mark = cur_row_error + cols;
210
    next_row_err_mark = next_row_error + cols;
211
 
212
    /* Process each column... */
213
 
214
    for (j=0; j<cols; j++) {
215
 
216
      pixsum = *cur_row + *cur_row_err_mark;
217
      if (pixsum < 0) pixsum = 0;
218
      else if (pixsum > 255) pixsum = 255;
219
 
220
      *dest_row = lum_index[pixsum].value;
221
      *(cur_row_err_mark-1) += lum_index[pixsum].e1;
222
      *next_row_err_mark += lum_index[pixsum].e3;
223
 
224
      cur_row--;
225
      dest_row--;
226
      cur_row_err_mark--;
227
      next_row_err_mark--;
228
    }
229
 
230
    /* Switch error arrays. */
231
 
232
    temp = cur_row_error;
233
    cur_row_error = next_row_error;
234
    next_row_error = temp;
235
 
236
    /* Reset next row errors. */
237
 
238
    memset(next_row_error, 0, cols+2);
239
  }
240
 
241
  /* Reset error arrays. */
242
 
243
  memset(cur_row_error, 0, cols+2);
244
 
245
  /* Establish column length divided by two. */
246
 
247
  c_cols = cols >> 1;
248
 
249
  /* Set channel to Cr. Use Cr index. */
250
 
251
  channel = cr;
252
  chan_index = cr_index;
253
 
254
 repeat:
255
 
256
  /* Process each row of chrominance data... */
257
 
258
  for (i=0; i < rows; i+=2) {
259
 
260
    /* Establish pointers. */
261
 
262
    cur_row = channel + ((i>>1)*c_cols);
263
    dest_row = disp + (i*cols);
264
 
265
    cur_row_err_mark = cur_row_error+1;
266
    next_row_err_mark = next_row_error+1;
267
 
268
    /* For each column in row... */
269
 
270
    for (j=0; j<cols; j++) {
271
      int p_val;
272
 
273
      /* Get pixel value as twos bit complement. */
274
 
275
      p_val = *cur_row;
276
 
277
      /* Add error term. */
278
 
279
      pixsum = *cur_row_err_mark + p_val;
280
 
281
      /* Bounds check. */
282
 
283
      if (pixsum < 0) pixsum = 0;
284
      else if (pixsum > 255) pixsum = 255;
285
 
286
      /* Increment dest value. */
287
 
288
      *dest_row += chan_index[pixsum].value;
289
 
290
      /* Propogate error values. */
291
 
292
      *(cur_row_err_mark+1) += chan_index[pixsum].e1;
293
      *next_row_err_mark += chan_index[pixsum].e3;
294
 
295
 
296
      /* If count is odd, advance source pointer (Cr and Cb channels are 2:1
297
         subsampled.
298
      */
299
 
300
      if (j&1) cur_row++;
301
 
302
      /* Advance destination and error pointers. */
303
 
304
      dest_row++;
305
      cur_row_err_mark++;
306
      next_row_err_mark++;
307
    }
308
 
309
    /* Switch error arrays. */
310
 
311
    temp = cur_row_error;
312
    cur_row_error = next_row_error;
313
    next_row_error = temp;
314
 
315
    /* Reset next row errors. */
316
 
317
    memset(next_row_error, 0, cols+2);
318
 
319
    /* Re-establish pointers. */
320
 
321
    cur_row += c_cols-1;
322
    dest_row += cols-1;
323
    cur_row_err_mark = cur_row_error+cols;
324
    next_row_err_mark = next_row_error+cols;
325
 
326
    /* Process second row right to left. */
327
 
328
    for (j=0; j<cols; j++) {
329
      int p_val;
330
 
331
      /* Get source value as twos bit complement. */
332
 
333
      p_val = *cur_row;
334
 
335
      /* Add error. */
336
 
337
      pixsum = *cur_row_err_mark + p_val;
338
 
339
      /* Bounds check. */
340
 
341
      if (pixsum < 0) pixsum = 0;
342
      else if (pixsum > 255) pixsum = 255;
343
 
344
      /* Increment dest value. */
345
 
346
      *dest_row += chan_index[pixsum].value;
347
 
348
      /* Propogate errors. */
349
 
350
      *(cur_row_err_mark-1) += chan_index[pixsum].e1;
351
      *next_row_err_mark += chan_index[pixsum].e3;
352
 
353
      /* If column counters is odd, decrement source pointer. */
354
 
355
      if (j&1) cur_row--;
356
 
357
      /* Decrement dest and error pointers. */
358
 
359
      dest_row--;
360
      cur_row_err_mark--;
361
      next_row_err_mark--;
362
    }
363
 
364
    /* Switch error arrays. */
365
 
366
    temp = cur_row_error;
367
    cur_row_error = next_row_error;
368
    next_row_error = temp;
369
 
370
    /* Reinitialize next row errors. */
371
 
372
    memset(next_row_error, 0, cols+2);
373
  }
374
 
375
  /* If Cr channel completed, set channel to Cb and Cb index and repeat. */
376
 
377
  if (channel == cr) {
378
    channel = cb;
379
    chan_index = cb_index;
380
    memset(cur_row_error, 0, cols+2);
381
 
382
    goto repeat;
383
  }
384
 
385
  /* Establish pointer to start of display frame. */
386
 
387
  dest_row = disp;
388
 
389
  /* Transform all display values to pixel values. */
390
 
391
  for (i=0; i<rows; i++) {
392
    for (j=0; j<cols; j++) {
393
      *dest_row =  pixel[*dest_row];
394
      dest_row++;
395
    }
396
  }
397
}