1 /* sane - Scanner Access Now Easy.
2    Copyright (C) 2002 Henning Meier-Geinitz <henning@meier-geinitz.de>
3    This file is part of the SANE package.
4 
5    This program is free software; you can redistribute it and/or
6    modify it under the terms of the GNU General Public License as
7    published by the Free Software Foundation; either version 2 of the
8    License, or (at your option) any later version.
9 
10    This program is distributed in the hope that it will be useful, but
11    WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    General Public License for more details.
14 
15    You should have received a copy of the GNU General Public License
16    along with this program.  If not, see <https://www.gnu.org/licenses/>.
17 
18    As a special exception, the authors of SANE give permission for
19    additional uses of the libraries contained in this release of SANE.
20 
21    The exception is that, if you link a SANE library with other files
22    to produce an executable, this does not by itself cause the
23    resulting executable to be covered by the GNU General Public
24    License.  Your use of that executable is in no way restricted on
25    account of linking the SANE library code into it.
26 
27    This exception does not, however, invalidate any other reasons why
28    the executable file might be covered by the GNU General Public
29    License.
30 
31    If you submit changes to SANE to the maintainers to be included in
32    a subsequent release, you agree by submitting the changes that
33    those changes may be distributed with this exception intact.
34 
35    If you write modifications of your own for SANE, it is your choice
36    whether to permit this exception to apply to your modifications.
37    If you do not wish that, delete this exception notice.
38 
39    This file implements test picture functions for the test backend.
40 */
41 
42 #define BUFFER_SIZE (64 * 1024)
43 
44 static SANE_Bool little_endian (void);
45 
46 static SANE_Status
init_picture_buffer(Test_Device * test_device, SANE_Byte ** buffer, size_t * buffer_size)47 init_picture_buffer (Test_Device * test_device, SANE_Byte ** buffer,
48 		     size_t * buffer_size)
49 {
50   SANE_Word pattern_size = 0, pattern_distance = 0;
51   SANE_Word line_count;
52   size_t b_size;
53   SANE_Word lines = 0;
54   SANE_Word bpl = test_device->bytes_per_line;
55   SANE_Word ppl = test_device->pixels_per_line;
56   SANE_Byte *b;
57   SANE_Bool is_little_endian = little_endian ();
58 
59   if (test_device->val[opt_invert_endianess].w)
60     is_little_endian ^= 1;
61 
62   DBG (2, "(child) init_picture_buffer test_device=%p, buffer=%p, "
63        "buffer_size=%p\n",(void*)test_device,(void*)buffer,(void*)buffer_size);
64 
65   if (strcmp (test_device->val[opt_test_picture].s, "Solid black") == 0
66       || strcmp (test_device->val[opt_test_picture].s, "Solid white") == 0)
67     {
68       SANE_Byte pattern = 0;
69 
70       b_size = BUFFER_SIZE;
71       if (buffer_size)
72 	*buffer_size = b_size;
73 
74       b = malloc (b_size);
75       if (!b)
76 	{
77 	  DBG (1, "(child) init_picture_buffer: couldn't malloc buffer\n");
78 	  return SANE_STATUS_NO_MEM;
79 	}
80 
81       if (buffer)
82 	*buffer = b;
83 
84       if (strcmp (test_device->val[opt_test_picture].s, "Solid black") == 0)
85 	{
86 	  DBG (3, "(child) init_picture_buffer: drawing solid black test "
87 	       "picture %zu bytes\n", b_size);
88 	  if (test_device->params.format == SANE_FRAME_GRAY
89 	      && test_device->params.depth == 1)
90 	    pattern = 0xff;
91 	  else
92 	    pattern = 0x00;
93 	}
94       else
95 	{
96 	  DBG (3, "(child) init_picture_buffer: drawing solid white test "
97 	       "picture %zu bytes\n", b_size);
98 	  if (test_device->params.format == SANE_FRAME_GRAY
99 	      && test_device->params.depth == 1)
100 	    pattern = 0x00;
101 	  else
102 	    pattern = 0xff;
103 	}
104       memset (b, pattern, b_size);
105       return SANE_STATUS_GOOD;
106     }
107 
108   /* Grid */
109   if (strcmp (test_device->val[opt_test_picture].s, "Grid") == 0)
110     {
111       double p_size = (10.0 * SANE_UNFIX (test_device->val[opt_resolution].w)
112 		       / MM_PER_INCH);
113       SANE_Word increment = 1;
114       if (test_device->params.format == SANE_FRAME_RGB)
115 	increment *= 3;
116       if (test_device->params.depth == 16)
117 	increment *= 2;
118 
119       lines = (SANE_Word) (2 * p_size + 0.5);
120       b_size = (size_t) lines * (size_t) bpl;
121       if (buffer_size)
122 	*buffer_size = b_size;
123       b = malloc (b_size);
124       if (!b)
125 	{
126 	  DBG (1, "(child) init_picture_buffer: couldn't malloc buffer\n");
127 	  return SANE_STATUS_NO_MEM;
128 	}
129       if (buffer)
130 	*buffer = b;
131       DBG (3, "(child) init_picture_buffer: drawing grid test picture "
132 	   "%zu bytes, %d bpl, %d ppl, %d lines\n", b_size, bpl, ppl, lines);
133 
134       for (line_count = 0; line_count < lines; line_count++)
135 	{
136 	  SANE_Word x = 0;
137 
138 	  for (x = 0; x < bpl; x += increment)
139 	    {
140 	      SANE_Word x1;
141 	      SANE_Byte color = 0;
142 
143 	      if (test_device->params.depth == 1)
144 		{
145 		  if (test_device->params.format == SANE_FRAME_GRAY ||
146 		      (test_device->params.format >= SANE_FRAME_RED &&
147 		       test_device->params.format <= SANE_FRAME_BLUE))
148 		    {
149 		      SANE_Byte value = 0;
150 		      for (x1 = 0; x1 < 8; x1++)
151 			{
152 			  SANE_Word xfull = x * 8 + (7 - x1);
153 
154 			  if (xfull < ppl)
155 			    {
156 			      if ((((SANE_Word) (xfull / p_size)) % 2)
157 				  ^ (!(line_count >
158 				      (SANE_Word) (p_size + 0.5))))
159 				color = 0x0;
160 			      else
161 				color = 0x1;
162 			    }
163 			  else
164 			    color = (rand ()) & 0x01;
165 			  value |= (SANE_Byte) (color << x1);
166 			}
167 		      b[line_count * bpl + x] = value;
168 		    }
169 		  else		/* SANE_FRAME_RGB */
170 		    {
171 		      SANE_Byte value = 0;
172 		      for (x1 = 0; x1 < 8; x1++)
173 			{
174 			  SANE_Word xfull = x * 8 / 3 + (7 - x1);
175 
176 			  if (xfull < ppl)
177 			    {
178 			      if (((SANE_Word) (xfull / p_size) % 2)
179 				  ^ (line_count > (SANE_Word) (p_size + 0.5)))
180 				color = 0x0;
181 			      else
182 				color = 0x1;
183 			    }
184 			  else
185 			    color = (rand ()) & 0x01;
186 			  value |= (SANE_Byte) (color << x1);
187 			}
188 		      for (x1 = 0; x1 < increment; x1++)
189 			b[line_count * bpl + x + x1] = value;
190 		    }
191 		}
192 	      else		/* depth = 8, 16 */
193 		{
194 		  if (x / increment < ppl)
195 		    if ((((SANE_Int) (x / increment / p_size)) % 2)
196 			^ (line_count > (SANE_Int) (p_size + 0.5)))
197 		      color = 0x00;
198 		    else
199 		      color = 0xff;
200 		  else
201 		    color = (SANE_Byte) ((rand ()) & 0xff);
202 
203 		  for (x1 = 0; x1 < increment; x1++)
204 		    b[line_count * bpl + x + x1] = color;
205 		}
206 	    }
207 	}
208       return SANE_STATUS_GOOD;
209     }
210 
211   /* Color patterns */
212   if (test_device->params.format == SANE_FRAME_GRAY
213       && test_device->params.depth == 1)
214     {
215       /* 1 bit black/white */
216       pattern_size = 16;
217       pattern_distance = 0;
218       lines = 2 * (pattern_size + pattern_distance);
219       b_size = (size_t) lines * (size_t) bpl;
220 
221       if (buffer_size)
222 	*buffer_size = b_size;
223       b = malloc (b_size);
224       if (!b)
225 	{
226 	  DBG (1, "(child) init_picture_buffer: couldn't malloc buffer\n");
227 	  return SANE_STATUS_NO_MEM;
228 	}
229       if (buffer)
230 	*buffer = b;
231       DBG (3, "(child) init_picture_buffer: drawing b/w test picture "
232 	   "%zu bytes, %d bpl, %d lines\n", b_size, bpl, lines);
233       memset (b, 255, b_size);
234       for (line_count = 0; line_count < lines; line_count++)
235 	{
236 	  SANE_Word x = 0;
237 
238 	  if (line_count >= lines / 2)
239 	    x += (pattern_size + pattern_distance) / 8;
240 
241 	  while (x < bpl)
242 	    {
243 	      SANE_Word width;
244 
245 	      width = pattern_size / 8;
246 	      if (x + width >= bpl)
247 		width = bpl - x;
248 	      memset (b + line_count * bpl + x, 0x00, (size_t) width);
249 	      x += (pattern_size + pattern_distance) * 2 / 8;
250 	    }
251 	}
252     }
253   else if (test_device->params.format == SANE_FRAME_GRAY
254 	   && test_device->params.depth == 8)
255     {
256       /* 8 bit gray */
257       pattern_size = 4;
258       pattern_distance = 1;
259       lines = 2 * (pattern_size + pattern_distance);
260       b_size = (size_t) lines * (size_t) bpl;
261 
262       if (buffer_size)
263 	*buffer_size = b_size;
264       b = malloc (b_size);
265       if (!b)
266 	{
267 	  DBG (1, "(child) init_picture_buffer: couldn't malloc buffer\n");
268 	  return SANE_STATUS_NO_MEM;
269 	}
270       if (buffer)
271 	*buffer = b;
272       DBG (3, "(child) init_picture_buffer: drawing 8 bit gray test picture "
273 	   "%zu bytes, %d bpl, %d lines\n", b_size, bpl, lines);
274       memset (b, 0x55, b_size);
275       for (line_count = 0; line_count < lines; line_count++)
276 	{
277 	  SANE_Word x = pattern_distance;
278 
279 	  if (line_count % (pattern_size + pattern_distance)
280 	      < pattern_distance)
281 	    continue;
282 
283 	  while (x < bpl)
284 	    {
285 	      SANE_Word width;
286 	      SANE_Byte color;
287 
288 	      width = pattern_size;
289 	      if (x + width >= bpl)
290 		width = bpl - x;
291 	      if (line_count > (pattern_size + pattern_distance))
292 		color =
293 		  (SANE_Byte) (0xff - ((x / (pattern_size + pattern_distance)) & 0xff));
294 	      else
295 		color = (SANE_Byte) ((x / (pattern_size + pattern_distance)) & 0xff);
296 	      memset (b + line_count * bpl + x, color, (size_t) width);
297 	      x += (pattern_size + pattern_distance);
298 	    }
299 	}
300 
301     }
302   else if (test_device->params.format == SANE_FRAME_GRAY
303 	   && test_device->params.depth == 16)
304     {
305       /* 16 bit gray */
306       pattern_size = 256;
307       pattern_distance = 4;
308       lines = 1 * (pattern_size + pattern_distance);
309       b_size = (size_t) lines * (size_t) bpl;
310 
311       if (buffer_size)
312 	*buffer_size = b_size;
313       b = malloc (b_size);
314       if (!b)
315 	{
316 	  DBG (1, "(child) init_picture_buffer: couldn't malloc buffer\n");
317 	  return SANE_STATUS_NO_MEM;
318 	}
319       if (buffer)
320 	*buffer = b;
321       DBG (3, "(child) init_picture_buffer: drawing 16 bit gray test picture "
322 	   "%zu bytes, %d bpl, %d lines\n", b_size, bpl, lines);
323       memset (b, 0x55, b_size);
324       for (line_count = 0; line_count < lines; line_count++)
325 	{
326 	  SANE_Word x = pattern_distance * 2;
327 
328 	  if (line_count % (pattern_size + pattern_distance)
329 	      < pattern_distance)
330 	    continue;
331 
332 	  while (x < bpl)
333 	    {
334 	      SANE_Word width;
335 	      SANE_Word x1;
336 	      SANE_Byte pattern_lo, pattern_hi;
337 
338 	      width = pattern_size * 2;
339 	      if (x + width >= bpl)
340 		width = bpl - x;
341 	      pattern_lo =
342 		(SANE_Byte) (((line_count - pattern_distance)
343 		 % (pattern_size + pattern_distance)) & 0xff);
344 	      for (x1 = 0; x1 < width; x1 += 2)
345 		{
346 		  pattern_hi = (SANE_Byte) ((x1 / 2) & 0xff);
347 		  if (is_little_endian)
348 		    {
349 		      b[line_count * bpl + x + x1 + 0] = pattern_lo;
350 		      b[line_count * bpl + x + x1 + 1] = pattern_hi;
351 		    }
352 		  else
353 		    {
354 		      b[line_count * bpl + x + x1 + 0] = pattern_hi;
355 		      b[line_count * bpl + x + x1 + 1] = pattern_lo;
356 		    }
357 		}
358 	      x += ((pattern_size + pattern_distance) * 2);
359 	    }
360 	}
361 
362     }
363   else if (test_device->params.format == SANE_FRAME_RGB
364 	   && test_device->params.depth == 1)
365     {
366       /* 1 bit color */
367       pattern_size = 16;
368       pattern_distance = 0;
369       lines = 2 * (pattern_size + pattern_distance);
370       b_size = (size_t) lines * (size_t) bpl;
371 
372       if (buffer_size)
373 	*buffer_size = b_size;
374       b = malloc (b_size);
375       if (!b)
376 	{
377 	  DBG (1, "(child) init_picture_buffer: couldn't malloc buffer\n");
378 	  return SANE_STATUS_NO_MEM;
379 	}
380       if (buffer)
381 	*buffer = b;
382       DBG (3, "(child) init_picture_buffer: drawing color lineart test "
383 	   "picture %zu bytes, %d bpl, %d lines\n", b_size, bpl, lines);
384       memset (b, 0x55, b_size);
385 
386       for (line_count = 0; line_count < lines; line_count++)
387 	{
388 	  SANE_Word x = 0;
389 	  SANE_Byte color = 0, color_r = 0, color_g = 0, color_b = 0;
390 
391 	  if (line_count >= lines / 2)
392 	    color = 7;
393 	  while (x < bpl)
394 	    {
395 	      SANE_Word width;
396 	      SANE_Word x2 = 0;
397 
398 	      width = pattern_size / 8 * 3;
399 	      if (x + width >= bpl)
400 		width = bpl - x;
401 
402 	      color_b = (color & 1) * 0xff;
403 	      color_g = ((color >> 1) & 1) * 0xff;
404 	      color_r = ((color >> 2) & 1) * 0xff;
405 
406 	      for (x2 = 0; x2 < width; x2 += 3)
407 		{
408 		  b[line_count * bpl + x + x2 + 0] = color_r;
409 		  b[line_count * bpl + x + x2 + 1] = color_g;
410 		  b[line_count * bpl + x + x2 + 2] = color_b;
411 		}
412 	      if (line_count < lines / 2)
413 		{
414 		  ++color;
415 		  if (color >= 8)
416 		    color = 0;
417 		}
418 	      else
419 		{
420 		  if (color == 0)
421 		    color = 8;
422 		  --color;
423 		}
424 	      x += ((pattern_size + pattern_distance) / 8 * 3);
425 	    }
426 	}
427     }
428   else if ((test_device->params.format == SANE_FRAME_RED
429 	    || test_device->params.format == SANE_FRAME_GREEN
430 	    || test_device->params.format == SANE_FRAME_BLUE)
431 	   && test_device->params.depth == 1)
432     {
433       /* 1 bit color three-pass */
434       pattern_size = 16;
435       pattern_distance = 0;
436       lines = 2 * (pattern_size + pattern_distance);
437       b_size = (size_t) lines * (size_t) bpl;
438 
439       if (buffer_size)
440 	*buffer_size = b_size;
441       b = malloc (b_size);
442       if (!b)
443 	{
444 	  DBG (1, "(child) init_picture_buffer: couldn't malloc buffer\n");
445 	  return SANE_STATUS_NO_MEM;
446 	}
447       if (buffer)
448 	*buffer = b;
449       DBG (3, "(child) init_picture_buffer: drawing color lineart three-pass "
450 	   "test picture %zu bytes, %d bpl, %d lines\n", b_size, bpl, lines);
451       memset (b, 0x55, b_size);
452 
453       for (line_count = 0; line_count < lines; line_count++)
454 	{
455 	  SANE_Word x = 0;
456 	  SANE_Byte color = 0, color_r = 0, color_g = 0, color_b = 0;
457 
458 	  if (line_count >= lines / 2)
459 	    color = 7;
460 	  while (x < bpl)
461 	    {
462 	      SANE_Word width;
463 	      SANE_Word x2 = 0;
464 
465 	      width = pattern_size / 8;
466 	      if (x + width >= bpl)
467 		width = bpl - x;
468 
469 	      color_b = (color & 1) * 0xff;
470 	      color_g = ((color >> 1) & 1) * 0xff;
471 	      color_r = ((color >> 2) & 1) * 0xff;
472 
473 	      for (x2 = 0; x2 < width; x2++)
474 		{
475 		  if (test_device->params.format == SANE_FRAME_RED)
476 		    b[line_count * bpl + x + x2] = color_r;
477 		  else if (test_device->params.format == SANE_FRAME_GREEN)
478 		    b[line_count * bpl + x + x2] = color_g;
479 		  else
480 		    b[line_count * bpl + x + x2] = color_b;
481 		}
482 	      if (line_count < lines / 2)
483 		{
484 		  ++color;
485 		  if (color >= 8)
486 		    color = 0;
487 		}
488 	      else
489 		{
490 		  if (color == 0)
491 		    color = 8;
492 		  --color;
493 		}
494 	      x += (pattern_size + pattern_distance) / 8;
495 	    }
496 	}
497     }
498   else if (test_device->params.format == SANE_FRAME_RGB
499 	   && test_device->params.depth == 8)
500     {
501       /* 8 bit color */
502       pattern_size = 4;
503       pattern_distance = 1;
504       lines = 6 * (pattern_size + pattern_distance);
505       b_size = (size_t) lines * (size_t) bpl;
506 
507       if (buffer_size)
508 	*buffer_size = b_size;
509       b = malloc (b_size);
510       if (!b)
511 	{
512 	  DBG (1, "(child) init_picture_buffer: couldn't malloc buffer\n");
513 	  return SANE_STATUS_NO_MEM;
514 	}
515       if (buffer)
516 	*buffer = b;
517       DBG (3, "(child) init_picture_buffer: drawing 8 bit color test picture "
518 	   "%zu bytes, %d bpl, %d lines\n", b_size, bpl, lines);
519       memset (b, 0x55, b_size);
520       for (line_count = 0; line_count < lines; line_count++)
521 	{
522 	  SANE_Word x = pattern_distance * 3;
523 
524 	  if (line_count % (pattern_size + pattern_distance)
525 	      < pattern_distance)
526 	    continue;
527 
528 	  while (x < bpl)
529 	    {
530 	      SANE_Word width;
531 	      SANE_Byte color = 0, color_r = 0, color_g = 0, color_b = 0;
532 	      SANE_Word x1;
533 
534 	      width = pattern_size * 3;
535 	      if (x + width >= bpl)
536 		width = bpl - x;
537 
538 	      if ((line_count / (pattern_size + pattern_distance)) & 1)
539 		color =
540 		  (SANE_Byte) (0xff - ((x / ((pattern_size + pattern_distance) * 3))
541 			  & 0xff));
542 	      else
543 		color = (SANE_Byte) ((x / ((pattern_size + pattern_distance) * 3)) & 0xff);
544 
545 	      if (line_count / (pattern_size + pattern_distance) < 2)
546 		{
547 		  color_r = color;
548 		  color_g = 0;
549 		  color_b = 0;
550 		}
551 	      else if (line_count / (pattern_size + pattern_distance) < 4)
552 		{
553 		  color_r = 0;
554 		  color_g = color;
555 		  color_b = 0;
556 		}
557 	      else
558 		{
559 		  color_r = 0;
560 		  color_g = 0;
561 		  color_b = color;
562 		}
563 
564 	      for (x1 = 0; x1 < width; x1 += 3)
565 		{
566 		  b[line_count * bpl + x + x1 + 0] = color_r;
567 		  b[line_count * bpl + x + x1 + 1] = color_g;
568 		  b[line_count * bpl + x + x1 + 2] = color_b;
569 		}
570 
571 	      x += ((pattern_size + pattern_distance) * 3);
572 	    }
573 	}
574 
575     }
576   else if ((test_device->params.format == SANE_FRAME_RED
577 	    || test_device->params.format == SANE_FRAME_GREEN
578 	    || test_device->params.format == SANE_FRAME_BLUE)
579 	   && test_device->params.depth == 8)
580     {
581       /* 8 bit color three-pass */
582       pattern_size = 4;
583       pattern_distance = 1;
584       lines = 6 * (pattern_size + pattern_distance);
585       b_size = (size_t) lines * (size_t) bpl;
586 
587       if (buffer_size)
588 	*buffer_size = b_size;
589       b = malloc (b_size);
590       if (!b)
591 	{
592 	  DBG (1, "(child) init_picture_buffer: couldn't malloc buffer\n");
593 	  return SANE_STATUS_NO_MEM;
594 	}
595       if (buffer)
596 	*buffer = b;
597       DBG (3, "(child) init_picture_buffer: drawing 8 bit color three-pass "
598 	   "test picture %zu bytes, %d bpl, %d lines\n", b_size, bpl, lines);
599       memset (b, 0x55, b_size);
600       for (line_count = 0; line_count < lines; line_count++)
601 	{
602 	  SANE_Word x = pattern_distance;
603 
604 	  if (line_count % (pattern_size + pattern_distance)
605 	      < pattern_distance)
606 	    continue;
607 
608 	  while (x < bpl)
609 	    {
610 	      SANE_Word width;
611 	      SANE_Byte color = 0;
612 
613 	      width = pattern_size;
614 	      if (x + width >= bpl)
615 		width = bpl - x;
616 
617 	      if ((line_count / (pattern_size + pattern_distance)) & 1)
618 		color = (SANE_Byte)
619 		  (0xff - (x / ((pattern_size + pattern_distance)) & 0xff));
620 	      else
621 		color = (SANE_Byte) ((x / (pattern_size + pattern_distance)) & 0xff);
622 
623 	      if (line_count / (pattern_size + pattern_distance) < 2)
624 		{
625 		  if (test_device->params.format != SANE_FRAME_RED)
626 		    color = 0x00;
627 		}
628 	      else if (line_count / (pattern_size + pattern_distance) < 4)
629 		{
630 		  if (test_device->params.format != SANE_FRAME_GREEN)
631 		    color = 0x00;
632 		}
633 	      else
634 		{
635 		  if (test_device->params.format != SANE_FRAME_BLUE)
636 		    color = 0x00;
637 		}
638 	      memset (b + line_count * bpl + x, color, (size_t) width);
639 
640 	      x += (pattern_size + pattern_distance);
641 	    }
642 	}
643     }
644   else if (test_device->params.format == SANE_FRAME_RGB
645 	   && test_device->params.depth == 16)
646     {
647       /* 16 bit color */
648       pattern_size = 256;
649       pattern_distance = 4;
650       lines = pattern_size + pattern_distance;
651       b_size = (size_t) lines * (size_t) bpl;
652 
653       if (buffer_size)
654 	*buffer_size = b_size;
655       b = malloc (b_size);
656       if (!b)
657 	{
658 	  DBG (1, "(child) init_picture_buffer: couldn't malloc buffer\n");
659 	  return SANE_STATUS_NO_MEM;
660 	}
661       if (buffer)
662 	*buffer = b;
663       DBG (3,
664 	   "(child) init_picture_buffer: drawing 16 bit color test picture "
665 	   "%zu bytes, %d bpl, %d lines\n", b_size, bpl, lines);
666       memset (b, 0x55, b_size);
667       for (line_count = 0; line_count < lines; line_count++)
668 	{
669 	  SANE_Word x = pattern_distance * 2 * 3;
670 
671 	  if (line_count % (pattern_size + pattern_distance)
672 	      < pattern_distance)
673 	    continue;
674 
675 	  while (x < bpl)
676 	    {
677 	      SANE_Word width;
678 	      SANE_Word x1;
679 	      SANE_Byte color_hi = 0, color_lo = 0;
680 	      SANE_Byte color_hi_r = 0, color_lo_r = 0;
681 	      SANE_Byte color_hi_g = 0, color_lo_g = 0;
682 	      SANE_Byte color_hi_b = 0, color_lo_b = 0;
683 
684 	      width = pattern_size * 2 * 3;
685 	      if (x + width >= bpl)
686 		width = bpl - x;
687 
688 
689 	      for (x1 = 0; x1 < width; x1 += 6)
690 		{
691 		  color_lo = (SANE_Byte)
692 		    (((line_count + pattern_size)
693 		     % (pattern_size + pattern_distance)) & 0xff);
694 		  color_hi = (SANE_Byte) ((x1 / 6) & 0xff);
695 		  if (((x / ((pattern_size + pattern_distance) * 6)) % 3) ==
696 		      0)
697 		    {
698 		      color_lo_r = color_lo;
699 		      color_hi_r = color_hi;
700 		      color_lo_g = 0;
701 		      color_hi_g = 0;
702 		      color_lo_b = 0;
703 		      color_hi_b = 0;
704 		    }
705 		  else if (((x / ((pattern_size + pattern_distance) * 6)) % 3)
706 			   == 1)
707 		    {
708 		      color_lo_r = 0;
709 		      color_hi_r = 0;
710 		      color_lo_g = color_lo;
711 		      color_hi_g = color_hi;
712 		      color_lo_b = 0;
713 		      color_hi_b = 0;
714 		    }
715 		  else
716 		    {
717 		      color_lo_r = 0;
718 		      color_hi_r = 0;
719 		      color_lo_g = 0;
720 		      color_hi_g = 0;
721 		      color_lo_b = color_lo;
722 		      color_hi_b = color_hi;
723 		    }
724 		  if (is_little_endian)
725 		    {
726 		      b[line_count * bpl + x + x1 + 0] = color_lo_r;
727 		      b[line_count * bpl + x + x1 + 1] = color_hi_r;
728 		      b[line_count * bpl + x + x1 + 2] = color_lo_g;
729 		      b[line_count * bpl + x + x1 + 3] = color_hi_g;
730 		      b[line_count * bpl + x + x1 + 4] = color_lo_b;
731 		      b[line_count * bpl + x + x1 + 5] = color_hi_b;
732 		    }
733 		  else
734 		    {
735 		      b[line_count * bpl + x + x1 + 0] = color_hi_r;
736 		      b[line_count * bpl + x + x1 + 1] = color_lo_r;
737 		      b[line_count * bpl + x + x1 + 2] = color_hi_g;
738 		      b[line_count * bpl + x + x1 + 3] = color_lo_g;
739 		      b[line_count * bpl + x + x1 + 4] = color_hi_b;
740 		      b[line_count * bpl + x + x1 + 5] = color_lo_b;
741 		    }
742 		}
743 	      x += ((pattern_size + pattern_distance) * 2 * 3);
744 	    }
745 	}
746 
747     }
748   else if ((test_device->params.format == SANE_FRAME_RED
749 	    || test_device->params.format == SANE_FRAME_GREEN
750 	    || test_device->params.format == SANE_FRAME_BLUE)
751 	   && test_device->params.depth == 16)
752     {
753       /* 16 bit color three-pass */
754       pattern_size = 256;
755       pattern_distance = 4;
756       lines = pattern_size + pattern_distance;
757       b_size = (size_t) lines * (size_t) bpl;
758 
759       if (buffer_size)
760 	*buffer_size = b_size;
761       b = malloc (b_size);
762       if (!b)
763 	{
764 	  DBG (1, "(child) init_picture_buffer: couldn't malloc buffer\n");
765 	  return SANE_STATUS_NO_MEM;
766 	}
767       if (buffer)
768 	*buffer = b;
769       DBG (3, "(child) init_picture_buffer: drawing 16 bit color three-pass "
770 	   "test picture %zu bytes, %d bpl, %d lines\n", b_size, bpl, lines);
771       memset (b, 0x55, b_size);
772       for (line_count = 0; line_count < lines; line_count++)
773 	{
774 	  SANE_Word x = pattern_distance * 2;
775 
776 	  if (line_count % (pattern_size + pattern_distance)
777 	      < pattern_distance)
778 	    continue;
779 
780 	  while (x < bpl)
781 	    {
782 	      SANE_Word width;
783 	      SANE_Word x1;
784 	      SANE_Byte color_hi = 0, color_lo = 0;
785 
786 	      width = pattern_size * 2;
787 	      if (x + width >= bpl)
788 		width = bpl - x;
789 
790 
791 	      for (x1 = 0; x1 < width; x1 += 2)
792 		{
793 		  color_lo = (SANE_Byte)
794 		    (((line_count + pattern_size)
795 		     % (pattern_size + pattern_distance)) & 0xff);
796 		  color_hi = (SANE_Byte) ((x1 / 2) & 0xff);
797 		  if (((x / ((pattern_size + pattern_distance) * 2)) % 3) ==
798 		      0)
799 		    {
800 		      if (test_device->params.format != SANE_FRAME_RED)
801 			{
802 			  color_lo = 0x00;
803 			  color_hi = 0x00;
804 			}
805 		    }
806 		  else if (((x / ((pattern_size + pattern_distance) * 2)) % 3)
807 			   == 1)
808 		    {
809 		      if (test_device->params.format != SANE_FRAME_GREEN)
810 			{
811 			  color_lo = 0x00;
812 			  color_hi = 0x00;
813 			}
814 		    }
815 		  else
816 		    {
817 		      if (test_device->params.format != SANE_FRAME_BLUE)
818 			{
819 			  color_lo = 0x00;
820 			  color_hi = 0x00;
821 			}
822 		    }
823 
824 		  if (is_little_endian)
825 		    {
826 		      b[line_count * bpl + x + x1 + 0] = color_lo;
827 		      b[line_count * bpl + x + x1 + 1] = color_hi;
828 		    }
829 		  else
830 		    {
831 		      b[line_count * bpl + x + x1 + 0] = color_hi;
832 		      b[line_count * bpl + x + x1 + 1] = color_lo;
833 		    }
834 
835 		}
836 	      x += ((pattern_size + pattern_distance) * 2);
837 	    }
838 	}
839 
840     }
841   else				/* Huh? */
842     {
843       DBG (1, "(child) init_picture_buffer: unknown mode\n");
844       return SANE_STATUS_INVAL;
845     }
846 
847   return SANE_STATUS_GOOD;
848 }
849