1 package de.desy.acop.video.displayer;
2
3 import java.awt.Graphics2D;
4 import java.awt.Image;
5 import java.awt.MediaTracker;
6 import java.awt.Toolkit;
7 import java.awt.image.BufferedImage;
8 import java.awt.image.MemoryImageSource;
9 import java.util.Arrays;
10
11 import de.desy.tine.types.IMAGE;
12 import de.desy.tine.types.IMAGE.FrameHeader;
13
14
15
16
17
18
19
20
21 public class ImageBuffer {
22
23
24
25
26 private int[] _pixels;
27
28
29
30
31
32 private MemoryImageSource _memorySource;
33
34
35
36
37 private Image _image;
38
39
40
41
42 private int[] _colorLookupTable;
43
44
45
46
47
48 private boolean _enabledNormalization;
49
50
51
52
53 private int _width, _height;
54
55
56
57
58 public ImageBuffer() {
59 super();
60 }
61
62
63
64
65
66
67 public int[] getPixels() {
68 return _pixels;
69 }
70
71
72
73
74
75
76 public void setPixels(int[] pixels) {
77 _pixels = pixels;
78 }
79
80
81
82
83
84
85
86
87 public boolean isEnabledNormalization() {
88 return _enabledNormalization;
89 }
90
91
92
93
94
95
96
97
98 public void setEnabledNormalization(boolean enabledNormalization) {
99 _enabledNormalization = enabledNormalization;
100 }
101
102
103
104
105 public int[] getColorLookupTable() {
106 return _colorLookupTable;
107 }
108
109
110
111
112
113 public void setColorLookupTable(int[] rgbArray) {
114 _colorLookupTable = rgbArray;
115 }
116
117
118
119
120
121
122
123
124
125
126
127 public Image createImage(IMAGE timage) {
128 if (timage == null)
129 throw new IllegalArgumentException("timage == null!");
130
131 FrameHeader hdr = timage.getFrameHeader();
132
133
134 if (ImageFormat.IMAGE_FORMAT_HUFFYUV.equals(hdr.imageFormat)
135 && ImageFormat.IMAGE_FORMAT_GRAY.equals(hdr.sourceFormat))
136 uncompressImage(timage);
137
138 ImageFormat imageFormat = ImageFormat.valueOf(hdr.imageFormat);
139 if (!imageFormat.isSupported())
140 throw new IllegalArgumentException("unsupported image format: " + imageFormat);
141
142 int width = (hdr.aoiWidth != -1) ? hdr.aoiWidth : hdr.sourceWidth;
143 int height = (hdr.aoiHeight != -1) ? hdr.aoiHeight : hdr.sourceHeight;
144
145 if (_pixels == null || width != _width || height != _height) {
146 _pixels = new int[width * height];
147 _memorySource = null;
148 }
149 _width = width;
150 _height = height;
151
152 byte[] buff = timage.getImageFrameBuffer();
153 buff = Arrays.copyOf(buff, hdr.appendedFrameSize);
154 if (buff == null)
155 throw new NullPointerException("buff == null!");
156
157 switch (imageFormat) {
158 case IMAGE_FORMAT_GRAY:
159 fillGray(buff, hdr.bytesPerPixel, hdr.effectiveBitsPerPixel);
160 break;
161
162 case IMAGE_FORMAT_RGB:
163 fillRGB(buff);
164 break;
165
166 case IMAGE_FORMAT_RGBA:
167 fillRGBA(buff);
168 break;
169
170 case IMAGE_FORMAT_JPEG:
171 fillJPEG(buff, hdr.bytesPerPixel, hdr.effectiveBitsPerPixel);
172 break;
173
174 default:
175 break;
176 }
177
178
179 if (_memorySource == null) {
180 _memorySource = new MemoryImageSource(_width, _height, _pixels, 0, _width);
181 _memorySource.setAnimated(true);
182 _memorySource.setFullBufferUpdates(true);
183 _image = Toolkit.getDefaultToolkit().createImage(_memorySource);
184
185 } else
186 _memorySource.newPixels();
187
188 return _image;
189 }
190
191
192
193
194
195
196
197 private void uncompressImage(IMAGE timage) {
198
199 FrameHeader fHdr = timage.getFrameHeader();
200 int uncompressed_byte_length = fHdr.bytesPerPixel
201 * ((fHdr.aoiWidth != -1) ? fHdr.aoiWidth : fHdr.sourceWidth)
202 * ((fHdr.aoiHeight != -1) ? fHdr.aoiHeight : fHdr.sourceHeight);
203
204 byte[] compressedBuf = new byte[fHdr.appendedFrameSize];
205
206 System.arraycopy(timage.getImageFrameBuffer(), 0, compressedBuf, 0, fHdr.appendedFrameSize);
207
208
209 HuffmanDecompression.decompressHuffYUV(compressedBuf, 0, timage.getImageFrameBuffer(), 0,
210 uncompressed_byte_length);
211
212
213 fHdr.imageFormat = ImageFormat.IMAGE_FORMAT_GRAY.getId();
214 fHdr.appendedFrameSize = uncompressed_byte_length;
215 timage.getSourceHeader().totalLength = uncompressed_byte_length + IMAGE.HEADER_SIZE;
216 }
217
218
219
220
221
222
223
224 private void fillRGB(byte[] buff) {
225
226 int index = 0;
227 int offset = 0;
228 try {
229 for (;;) {
230 int red = buff[offset++] & 0xFF;
231 int green = buff[offset++] & 0xFF;
232 int blue = buff[offset++] & 0xFF;
233 _pixels[index++] = 0xFF000000 | (red << 16) | (green << 8) | blue;
234 }
235 } catch (ArrayIndexOutOfBoundsException ignored) {
236
237 }
238
239
240 if (_enabledNormalization)
241 normalize();
242 }
243
244
245
246
247
248
249
250
251 private void fillRGBA(byte[] buff) {
252 System.arraycopy(java.nio.ByteBuffer.wrap(buff).asIntBuffer(), 0, _pixels, 0, _pixels.length);
253
254
255 if (_enabledNormalization)
256 normalize();
257 }
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277 private boolean fillJPEG(byte[] buff, int bytesPerPixel, int effBitsPerPixel) {
278 BufferedImage bi = null;
279 Image image = Toolkit.getDefaultToolkit().createImage(buff);
280 MediaTracker tracker = new MediaTracker(null);
281 tracker.addImage(image, 0);
282 try {
283 tracker.waitForID(0);
284
285 } catch (InterruptedException e) {
286 throw new RuntimeException("Image creation has been interrupted, message: " + e.getMessage());
287 }
288
289 if (bytesPerPixel == 1) {
290 bi = new BufferedImage(_width, _height, BufferedImage.TYPE_BYTE_GRAY);
291
292 Graphics2D bufImageGraphics = bi.createGraphics();
293 bufImageGraphics.drawImage(image, 0, 0, null);
294
295
296 int imgWidth = bi.getWidth();
297 int imgHeight = bi.getHeight();
298
299 if (imgWidth != _width || imgHeight != _height)
300 return false;
301
302 byte[] buffNew = new byte[imgWidth * imgHeight];
303 byte[] pix = new byte[1];
304
305 int i = 0;
306
307
308 for (int y = 0; y < imgHeight; y++) {
309
310 for (int x = 0; x < imgWidth; x++) {
311 bi.getRaster().getDataElements(x, y, pix);
312 buffNew[i++] = pix[0];
313 }
314
315 }
316 fillGray(buffNew, bytesPerPixel, effBitsPerPixel);
317
318 } else {
319 bi = new BufferedImage(_width, _height, BufferedImage.TYPE_INT_ARGB);
320
321 Graphics2D bufImageGraphics = bi.createGraphics();
322 bufImageGraphics.drawImage(image, 0, 0, null);
323
324
325 int imgWidth = bi.getWidth();
326 int imgHeight = bi.getHeight();
327
328 if (imgWidth != _width || imgHeight != _height
329 || bi.getRGB(0, 0, imgWidth, imgHeight, _pixels, 0, imgWidth) == null)
330 throw new RuntimeException("create JPEG image failed.");
331
332 if (_enabledNormalization)
333 normalize();
334 }
335 return true;
336 }
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353 private void fillGray(byte[] buff, int bytesPerPixel, int effBitsPerPixel) {
354
355 if (_enabledNormalization)
356 normalizeGray(buff, bytesPerPixel, effBitsPerPixel);
357
358 int[] colorLookupTable = _colorLookupTable;
359 if (colorLookupTable == null)
360 colorLookupTable = (new ColorLookupTable(ColorMap.GRAYSCALE, bytesPerPixel, effBitsPerPixel)).getRGB();
361
362
363
364
365
366 int index = 0;
367 int i = 0;
368 if (bytesPerPixel == 1) {
369 try {
370 for (;;) {
371 _pixels[index] = colorLookupTable[buff[index] & 0xff];
372 index++;
373 }
374 } catch (ArrayIndexOutOfBoundsException ignored) {
375
376 }
377
378 } else if (bytesPerPixel == 2) {
379 try {
380 for (;;) {
381 i = 2 * index;
382 _pixels[index++] = colorLookupTable[(buff[i] & 0xff) + ((buff[i + 1] & 0xff) << 8)];
383 }
384 } catch (ArrayIndexOutOfBoundsException ignored) {
385
386 }
387
388 } else {
389 try {
390 for (;;) {
391 i = 3 * index;
392 _pixels[index++] = colorLookupTable[(buff[i] & 0xff) + ((buff[i + 1] & 0xff) << 8)
393 + ((buff[i + 2] & 0xff) << 16)];
394 }
395 } catch (ArrayIndexOutOfBoundsException ignored) {
396
397 }
398 }
399 }
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418 private boolean normalize() {
419
420
421
422 double minY = 256.0;
423 double maxY = 0;
424 int x = 0;
425
426 try {
427 for (;;) {
428 int pixel = _pixels[x++];
429
430 int r = (pixel >> 16) & 0xff;
431 int g = (pixel >> 8) & 0xff;
432 int b = pixel & 0xff;
433
434 double Y = 0.299 * r + 0.587 * g + 0.114 * b;
435 if (Y < minY)
436 minY = Y;
437 if (Y > maxY)
438 maxY = Y;
439 }
440
441 } catch (ArrayIndexOutOfBoundsException ignored) {
442
443 }
444
445
446
447 int lowest = (int) minY;
448 int highest = (int) maxY;
449
450 if (lowest == highest)
451 return false;
452
453 double step = (255.0) / ((double) (maxY - minY));
454 double offset = -1.0 * step * minY;
455
456
457
458 x = 0;
459 try {
460 for (;;) {
461 int pixel = _pixels[x];
462
463 int r = (pixel >> 16) & 0xff;
464 int g = (pixel >> 8) & 0xff;
465 int b = pixel & 0xff;
466
467 double Y = 0.299 * r + 0.587 * g + 0.114 * b;
468 double Ynew = Y * step + offset;
469 double YnewdY = Ynew / Y;
470
471 int r2 = (int) (YnewdY * r);
472 int g2 = (int) (YnewdY * g);
473 int b2 = (int) (YnewdY * b);
474
475 if (r2 < 0)
476 r2 = 0;
477 if (g2 < 0)
478 g2 = 0;
479 if (b2 < 0)
480 b2 = 0;
481 if (r2 > 255)
482 r2 = 255;
483 if (g2 > 255)
484 g2 = 255;
485 if (b2 > 255)
486 b2 = 255;
487
488 _pixels[x++] = 0xFF000000 | (r2 << 16) | (g2 << 8) | (b2);
489 }
490
491 } catch (ArrayIndexOutOfBoundsException ignored) {
492
493 }
494
495 return true;
496 }
497
498
499
500
501
502
503
504
505 private void normalizeGray(byte[] buff, int bytesPerPixel, int effBitsPerPixel) {
506
507 int maxcol = (1 << effBitsPerPixel) - 1;
508
509
510 int lowest = maxcol;
511 int highest = 0;
512
513
514
515
516 int index = 0;
517 int bytelength = _pixels.length;
518
519 if (bytesPerPixel == 1) {
520 while (index < bytelength) {
521 int pixel = (buff[index] & maxcol);
522 if (pixel < lowest)
523 lowest = pixel;
524 if (pixel > highest && pixel <= maxcol)
525 highest = pixel;
526 index++;
527 }
528
529 } else if (bytesPerPixel == 2) {
530 bytelength *= 2;
531 while (index < bytelength) {
532 int pixel = ((buff[index]) & 0xff) + (((buff[index + 1]) & 0xff) << 8);
533 if (pixel < lowest)
534 lowest = pixel;
535 if (pixel > highest && pixel <= maxcol)
536 highest = pixel;
537 index += 2;
538 }
539
540 } else {
541 bytelength *= 3;
542 while (index < bytelength) {
543 int pixel = ((buff[index]) & 0xff) + (((buff[index + 1]) & 0xff) << 8)
544 + (((buff[index + 2]) & 0xff) << 16);
545 if (pixel < lowest)
546 lowest = pixel;
547 if (pixel > highest && pixel <= maxcol)
548 highest = pixel;
549 index += 3;
550 }
551 }
552
553 if (lowest == highest)
554 return;
555
556
557
558
559 double step = (double) maxcol / ((double) (highest - lowest));
560 int offset = (int) (-1.0 * step * lowest);
561
562
563
564 index = 0;
565 if (bytesPerPixel == 1) {
566 while (index < bytelength) {
567 int pixel = (buff[index] & 0xff);
568 if (pixel <= maxcol)
569 pixel = ((int) (step * (double) pixel)) + offset;
570 buff[index] = (byte) pixel;
571 index++;
572 }
573
574 } else if (bytesPerPixel == 2) {
575 while (index < bytelength) {
576 int pixel = (buff[index] & 0xff) + ((buff[index + 1] & 0xff) << 8);
577 if (pixel <= maxcol)
578 pixel = ((int) (step * (double) pixel)) + offset;
579 buff[index] = (byte) (pixel & 0xff);
580 buff[index + 1] = (byte) ((pixel >> 8) & 0xff);
581 index += 2;
582 }
583 } else {
584 while (index < bytelength) {
585 int pixel = (buff[index] & 0xff) + ((buff[index + 1] & 0xff) << 8) + ((buff[index + 2] & 0xff) << 16);
586 if (pixel <= maxcol)
587 pixel = ((int) (step * (double) pixel)) + offset;
588 buff[index] = (byte) (pixel & 0xff);
589 buff[index + 1] = (byte) ((pixel >> 8) & 0xff);
590 buff[index + 2] = (byte) ((pixel >> 16) & 0xff);
591 index += 3;
592 }
593 }
594 }
595
596
597
598
599 public void reset() {
600 this._memorySource = null;
601 this._pixels = null;
602 this._image = null;
603 }
604
605
606
607
608 public Image getImage() {
609 return _image;
610 }
611
612 }