View Javadoc

1   package de.desy.acop.video.displayer.timage;
2   
3   import java.awt.Graphics;
4   import java.awt.Graphics2D;
5   import java.awt.GraphicsConfiguration;
6   import java.awt.GraphicsDevice;
7   import java.awt.GraphicsEnvironment;
8   import java.awt.HeadlessException;
9   import java.awt.Image;
10  import java.awt.Toolkit;
11  import java.awt.Transparency;
12  import java.awt.color.ColorSpace;
13  import java.awt.geom.AffineTransform;
14  import java.awt.image.BufferedImage;
15  import java.awt.image.BufferedImageOp;
16  import java.awt.image.ColorConvertOp;
17  import java.awt.image.ColorModel;
18  import java.awt.image.DataBufferByte;
19  import java.awt.image.DataBufferInt;
20  import java.awt.image.DataBufferUShort;
21  import java.awt.image.FilteredImageSource;
22  import java.awt.image.ImageFilter;
23  import java.awt.image.ImageProducer;
24  import java.awt.image.RenderedImage;
25  import java.awt.image.WritableRaster;
26  import java.io.ByteArrayInputStream;
27  import java.io.ByteArrayOutputStream;
28  import java.io.IOException;
29  import java.util.Arrays;
30  
31  import javax.imageio.IIOImage;
32  import javax.imageio.ImageIO;
33  import javax.imageio.ImageReader;
34  import javax.imageio.ImageWriter;
35  import javax.imageio.stream.ImageInputStream;
36  import javax.imageio.stream.ImageOutputStream;
37  import javax.swing.GrayFilter;
38  import javax.swing.ImageIcon;
39  
40  import com.sun.imageio.plugins.png.PNGMetadata;
41  
42  import de.desy.acop.video.displayer.ColorMap;
43  import de.desy.acop.video.displayer.HuffmanDecompression;
44  import de.desy.acop.video.displayer.ImageFormat;
45  import de.desy.acop.video.timageio.TImageMetadata;
46  import de.desy.tine.types.IMAGE;
47  import de.desy.tine.types.IMAGE.FrameHeader;
48  import de.desy.tine.types.IMAGE.SourceHeader;
49  
50  public class TImageUtils {
51  
52  	/**
53  	 * Convenient static method to convert Image instances to BufferedImage
54  	 * instances.
55  	 * <p>
56  	 * If the specified image is already instance of BufferedImage then it's
57  	 * returned without processing.
58  	 * 
59  	 * @param image
60  	 *            - image to convert if it's necessary
61  	 * @return instance of BufferedImage or null if Image loading process is
62  	 *         failed
63  	 * @throws java.lang.NullPointerException
64  	 *             <code>image</code> is null
65  	 */
66  	public static final BufferedImage toBufferedImage(java.awt.Image image) {
67  		if (image == null)
68  			throw new NullPointerException("image == null!");
69  
70  		if (image instanceof BufferedImage)
71  			return (BufferedImage) image;
72  
73  		// This code ensures that all the pixels in the image are loaded
74  		image = new ImageIcon(image).getImage();
75  
76  		// Determine if the image has transparent pixels; for this method's
77  		// implementation, see e661 Determining If an Image Has Transparent
78  		// Pixels
79  		boolean hasAlpha = false;
80  
81  		// Create a buffered image with a format that's compatible with the
82  		// screen
83  		BufferedImage bi = null;
84  		GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
85  
86  		try {
87  			// Determine the type of transparency of the new buffered image
88  			int transparency = Transparency.OPAQUE;
89  			if (hasAlpha)
90  				transparency = Transparency.BITMASK;
91  
92  			// Create the buffered image
93  			GraphicsDevice gs = ge.getDefaultScreenDevice();
94  			GraphicsConfiguration gc = gs.getDefaultConfiguration();
95  			bi = gc.createCompatibleImage(image.getWidth(null), image.getHeight(null), transparency);
96  
97  		} catch (HeadlessException ignored) {
98  			// The system does not have a screen
99  		}
100 
101 		if (bi == null) {
102 			// Create a buffered image using the default color model
103 			int type = BufferedImage.TYPE_INT_RGB;
104 			if (hasAlpha)
105 				type = BufferedImage.TYPE_INT_ARGB;
106 
107 			bi = new BufferedImage(image.getWidth(null), image.getHeight(null), type);
108 		}
109 
110 		// Copy image to buffered image
111 		Graphics g = bi.createGraphics();
112 
113 		// Paint the image onto the buffered image
114 		g.drawImage(image, 0, 0, null);
115 		g.dispose();
116 
117 		return bi;
118 	}
119 
120 	/**
121 	 * Add the insets to the image and fill span between image and new borders.
122 	 * 
123 	 * @param src
124 	 *            - image to inset
125 	 * @param insets
126 	 *            - instance of Insets class
127 	 * @param paint
128 	 *            - to fill the span
129 	 * @return BufferedImage instance with added insets.
130 	 * @throws java.lang.NullPointerException
131 	 *             <ol>
132 	 *             <li>If <code>src</code> is null
133 	 *             <li>If <code>insets</code> is null
134 	 */
135 	public static final BufferedImage addInsets(BufferedImage src, java.awt.Insets insets, java.awt.Paint paint) {
136 		if (src == null)
137 			throw new NullPointerException("src == null!");
138 
139 		if (insets == null)
140 			throw new NullPointerException("insets == null!");
141 
142 		int w = src.getWidth();
143 		int h = src.getHeight();
144 
145 		BufferedImage dst = new BufferedImage(w + insets.left + insets.right, h + insets.top + insets.bottom, src
146 				.getType());
147 		Graphics2D g = dst.createGraphics();
148 		if (paint != null) {
149 			g.setPaint(paint);
150 			if (insets.left > 0)
151 				g.fillRect(0, 0, insets.left, h);
152 
153 			if (insets.right > 0)
154 				g.fillRect(w - insets.right, 0, insets.right, h);
155 
156 			if (insets.top > 0)
157 				g.fillRect(insets.left, 0, w - insets.left - insets.right, insets.top);
158 
159 			if (insets.bottom > 0)
160 				g.fillRect(insets.left, h - insets.bottom, w - insets.left - insets.right, insets.bottom);
161 		}
162 		g.drawRenderedImage(src, AffineTransform.getTranslateInstance(insets.left, insets.right));
163 		g.dispose();
164 		return dst;
165 	}
166 
167 	/**
168 	 * @param src
169 	 *            - image to scale
170 	 * @param dstWidth
171 	 *            - width which source image should be minimized to (the result
172 	 *            image can have less width if 'keepRatio' parameter set to
173 	 *            true)
174 	 * @param dstHeight
175 	 *            - height which source image should be minimized to (the result
176 	 *            image can have less height if 'keepRatio' parameter set to
177 	 *            true)
178 	 * @param keepRatio
179 	 *            -resize image proportionally
180 	 * @return new scaled instance of BufferedImage
181 	 * 
182 	 * @throws NullPointerException
183 	 *             If <code>src</code> is null
184 	 * 
185 	 * @throws java.lang.IllegalArgumentException
186 	 *             <ol>
187 	 *             <li>If <code>dstWidth</code> < 1
188 	 *             <li>If <code>dstHeight</code> < 1
189 	 */
190 	public static final java.awt.image.BufferedImage scale(java.awt.image.BufferedImage src, int dstWidth,
191 			int dstHeight, boolean keepRatio) {
192 		if (src == null)
193 			throw new NullPointerException("src == null!");
194 
195 		if (dstWidth < 1 || dstHeight < 1)
196 			throw new IllegalArgumentException((dstWidth < 1 ? "dstWidth" : "dstHeight") + " < 1!");
197 
198 		int srcWidth = src.getWidth();
199 		int srcHeight = src.getHeight();
200 
201 		Image scaleImage;
202 		if (keepRatio) {
203 			float ratio = (float) srcWidth / (float) srcHeight;
204 			if (ratio < (float) dstWidth / (float) dstHeight)
205 				dstWidth = (int) (dstHeight * ratio);
206 			else
207 				dstHeight = (int) (dstWidth * (1.0 / ratio));
208 
209 			if (dstWidth < 1)
210 				dstWidth = 1;
211 
212 			if (dstHeight < 1)
213 				dstHeight = 1;
214 		}
215 		scaleImage = src.getScaledInstance(dstWidth, dstHeight, Image.SCALE_FAST);
216 
217 		ColorModel dstCM = src.getColorModel();
218 		BufferedImage dst = new BufferedImage(dstCM, dstCM.createCompatibleWritableRaster(dstWidth, dstHeight), dstCM
219 				.isAlphaPremultiplied(), null);
220 		Graphics2D g = dst.createGraphics();
221 		g.drawImage(scaleImage, 0, 0, dstWidth, dstHeight, null);
222 		g.dispose();
223 		return dst;
224 	}
225 
226 	/**
227 	 * Writes an image using an arbitrary ImageWriter that supports the given
228 	 * format to a newly allocated byte array.
229 	 * 
230 	 * @param rimage
231 	 *            - a RenderedImage to be written.
232 	 * @param formatName
233 	 *            - a String contain the informal name of the format.
234 	 * 
235 	 * @return a newly allocated byte array
236 	 * @throws IOException
237 	 *             if an error occurs during writing.
238 	 */
239 	public static byte[] toRawBytes(RenderedImage rimage, String formatName) throws IOException {
240 		ByteArrayOutputStream baos = new ByteArrayOutputStream();
241 		byte[] rawBytes = null;
242 		try {
243 			ImageIO.write(rimage, formatName, baos);
244 			baos.flush();
245 			rawBytes = baos.toByteArray();
246 
247 		} finally {
248 			baos.close();
249 		}
250 		return rawBytes;
251 	}
252 
253 	/**
254 	 * Creates an Image from array using raster.
255 	 * 
256 	 * @param pixels
257 	 *            - The input int pixel array.
258 	 * @param width
259 	 *            - Width of the pixel rectangle.
260 	 * @param height
261 	 *            - Height of the pixel rectangle.
262 	 * @param type
263 	 *            - type of the created image
264 	 * @return Image
265 	 */
266 	public static Image getImageFromArray(int[] pixels, int width, int height, int type) {
267 		BufferedImage image = new BufferedImage(width, height, type);
268 		WritableRaster raster = (WritableRaster) image.getData();
269 		raster.setPixels(0, 0, width, height, pixels);
270 		return image;
271 	}
272 
273 	/**
274 	 * Get a byte array associated with input buffered image.
275 	 * 
276 	 * @param image
277 	 *            - input buffered image
278 	 * @return byte-array
279 	 */
280 	public static byte[] getImageByteArray(BufferedImage image) {
281 		WritableRaster raster = image.getRaster();
282 		DataBufferByte buffer = (DataBufferByte) raster.getDataBuffer();
283 		return buffer.getData();
284 	}
285 
286 	/**
287 	 * Get a integer array associated with input buffered image.
288 	 * 
289 	 * @param image
290 	 *            - input buffered image
291 	 * @return int-array
292 	 */
293 	public static int[] getImageIntArray(BufferedImage image) {
294 		WritableRaster raster = image.getRaster();
295 		DataBufferInt buffer = (DataBufferInt) raster.getDataBuffer();
296 		return buffer.getData();
297 	}
298 
299 	/**
300 	 * Create an PNG image bitmap.
301 	 * 
302 	 * @param image
303 	 *            The image to render.
304 	 * @param resolution
305 	 *            The DPI of the image.
306 	 * @param format
307 	 *            The format to convert to.
308 	 * @return A file image of the bitmap.
309 	 */
310 	public static byte[] imageToBitmap(BufferedImage image, float resolution, String format) throws IOException {
311 
312 		// define PNG resolution, etc.
313 		PNGMetadata png = new PNGMetadata();
314 		int res = (int) Math.ceil(resolution / 0.0254f);
315 		png.pHYs_pixelsPerUnitXAxis = res;
316 		png.pHYs_pixelsPerUnitYAxis = res;
317 		png.pHYs_unitSpecifier = 1;
318 		png.pHYs_present = true;
319 
320 		IIOImage iioImage = new IIOImage(image, null, png);
321 
322 		// Save as PNG
323 		ImageWriter writer = ImageIO.getImageWritersByFormatName(format).next();
324 		ByteArrayOutputStream out = new ByteArrayOutputStream();
325 		ImageOutputStream ios = ImageIO.createImageOutputStream(out);
326 		writer.setOutput(ios);
327 
328 		writer.write(iioImage);
329 		writer.dispose();
330 		return out.toByteArray();
331 	}
332 
333 	/**
334 	 * Convert a bitmap to an Image object
335 	 * 
336 	 * @param data
337 	 *            The bitmap file.
338 	 * @param format
339 	 *            The format the data is in.
340 	 * @return The Image of this data.
341 	 * @throws IOException
342 	 *             thrown if a problem reading the data or the format is wrong.
343 	 */
344 	public static BufferedImage bitmapToImage(byte[] data, String format) throws IOException {
345 		ByteArrayInputStream inb = new ByteArrayInputStream(data);
346 		ImageReader rdr = ImageIO.getImageReadersByFormatName(format).next();
347 		ImageInputStream imageInput = ImageIO.createImageInputStream(inb);
348 		rdr.setInput(imageInput);
349 		return rdr.read(0);
350 	}
351 
352 	public static BufferedImage convertToGrayscale(BufferedImage source) {
353 		BufferedImageOp op = new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_GRAY), null);
354 		return op.filter(source, null);
355 	}
356 
357 	public static BufferedImage convertToGrayscale2(BufferedImage colorImage) {
358 		BufferedImage bi = new BufferedImage(colorImage.getWidth(), colorImage.getHeight(),
359 				BufferedImage.TYPE_BYTE_GRAY);
360 		Graphics g = bi.getGraphics();
361 		g.drawImage(colorImage, 0, 0, null);
362 		g.dispose();
363 		return bi;
364 	}
365 
366 	public static Image convertToGrayscale3(BufferedImage colorImage) {
367 		ImageFilter filter = new GrayFilter(true, 50);
368 		ImageProducer producer = new FilteredImageSource(colorImage.getSource(), filter);
369 		Image image = Toolkit.getDefaultToolkit().createImage(producer);
370 		return image;
371 	}
372 
373 	/**
374 	 * Uncompresses the TINE image data.
375 	 * 
376 	 * @param timage
377 	 *            - input TINE IMAGE
378 	 * @return - uncompressed TINE IMAGE
379 	 */
380 	public static IMAGE uncompressImage(IMAGE timage) {
381 		if (timage == null)
382 			throw new NullPointerException("timage == null!");
383 
384 		final IMAGE ti = timage.clone();
385 
386 		FrameHeader fHdr = ti.getFrameHeader();
387 		SourceHeader sHdr = ti.getSourceHeader();
388 
389 		int uncompressed_byte_length = fHdr.bytesPerPixel //
390 				* ((fHdr.aoiWidth != -1) ? fHdr.aoiWidth : fHdr.sourceWidth) //
391 				* ((fHdr.aoiHeight != -1) ? fHdr.aoiHeight : fHdr.sourceHeight);
392 
393 		byte[] compressedBuf = new byte[fHdr.appendedFrameSize];
394 
395 		System.arraycopy(ti.getImageFrameBuffer(), 0, compressedBuf, 0, fHdr.appendedFrameSize);
396 
397 		// VideoHeaderV3.HDRSIZE
398 		HuffmanDecompression.decompressHuffYUV(compressedBuf, 0, timage.getImageFrameBuffer(), 0,
399 				uncompressed_byte_length);
400 
401 		// adjust header after compression
402 		fHdr.imageFormat = ImageFormat.IMAGE_FORMAT_GRAY.getId();
403 		fHdr.appendedFrameSize = uncompressed_byte_length;
404 		sHdr.totalLength = uncompressed_byte_length + IMAGE.HEADER_SIZE;
405 
406 		return ti;
407 	}
408 
409 	/**
410 	 * Creates and returns a copy of TINE image.
411 	 * 
412 	 * @deprecated mdavid: use {@link de.desy.tine.types.IMAGE#clone()} instead
413 	 * @return a copy of a <code>timage</code> TINE image.
414 	 */
415 	public static final IMAGE clone(IMAGE timage) {
416 		FrameHeader fHdr = timage.getFrameHeader();
417 		SourceHeader sHdr = timage.getSourceHeader();
418 		byte[] buffer = timage.getImageFrameBuffer();
419 		IMAGE ti = new IMAGE(buffer.length);
420 		setFrameHeader(ti, fHdr);
421 		setSourceHeader(ti, sHdr);
422 		byte[] clone = ti.getImageFrameBuffer();
423 		System.arraycopy(buffer, 0, clone, 0, clone.length);
424 		// ti.setImageFrameBuffer(timage.getImageFrameBuffer().clone());
425 		return ti;
426 	}
427 
428 	/**
429 	 * TODO: should be replaced/changed into IMAGE.FrameHeader class
430 	 * 
431 	 */
432 	public static final IMAGE setFrameHeader(IMAGE timage, FrameHeader fraHeader) {
433 		FrameHeader frameHeader = timage.getFrameHeader();
434 		frameHeader.aoiHeight = fraHeader.aoiHeight;
435 		frameHeader.aoiWidth = fraHeader.aoiWidth;
436 		frameHeader.appendedFrameSize = fraHeader.appendedFrameSize;
437 		frameHeader.bytesPerPixel = fraHeader.bytesPerPixel;
438 		frameHeader.effectiveBitsPerPixel = fraHeader.effectiveBitsPerPixel;
439 		frameHeader.eventNumber = fraHeader.eventNumber;
440 		frameHeader.frameNumber = fraHeader.frameNumber;
441 		frameHeader.fspare1 = fraHeader.fspare1;
442 		frameHeader.fspare2 = fraHeader.fspare2;
443 		frameHeader.fspare3 = fraHeader.fspare3;
444 		frameHeader.horizontalBinning = fraHeader.horizontalBinning;
445 		frameHeader.imageFlags = fraHeader.imageFlags;
446 		frameHeader.imageFormat = fraHeader.imageFormat;
447 		frameHeader.imageRotation = fraHeader.imageRotation;
448 		frameHeader.ispare1 = fraHeader.ispare1;
449 		frameHeader.ispare2 = fraHeader.ispare2;
450 		frameHeader.ispare3 = fraHeader.ispare3;
451 		frameHeader.sourceFormat = fraHeader.sourceFormat;
452 		frameHeader.sourceHeight = fraHeader.sourceHeight;
453 		frameHeader.sourceWidth = fraHeader.sourceWidth;
454 		frameHeader.verticalBinning = fraHeader.verticalBinning;
455 		frameHeader.xScale = fraHeader.xScale;
456 		frameHeader.xStart = fraHeader.xStart;
457 		frameHeader.yScale = fraHeader.yScale;
458 		frameHeader.yStart = fraHeader.yStart;
459 		return timage;
460 	}
461 
462 	/**
463 	 * TODO: should be replaced/changed into IMAGE.FrameHeader class
464 	 * 
465 	 */
466 	public static final IMAGE setSourceHeader(IMAGE timage, SourceHeader srcHeader) {
467 		SourceHeader sourceHeader = timage.getSourceHeader();
468 		sourceHeader.baseTag = srcHeader.baseTag;
469 		sourceHeader.cameraPortId = srcHeader.cameraPortId;
470 		sourceHeader.cameraPortName = srcHeader.cameraPortName;
471 		sourceHeader.timestampMicroseconds = srcHeader.timestampMicroseconds;
472 		sourceHeader.timestampSeconds = srcHeader.timestampSeconds;
473 		sourceHeader.totalLength = srcHeader.totalLength;
474 		sourceHeader.versionTag = srcHeader.versionTag;
475 		return timage;
476 	}
477 
478 	/**
479 	 ** Pad a string S with a size of N with char C on the left(True) or on the
480 	 * right(False)
481 	 */
482 	public static String padString(String s, int n, char c, boolean padLeft) {
483 		StringBuffer sb = new StringBuffer(s);
484 		int strLength = sb.length();
485 		if (n > 0 && n > strLength) {
486 			for (int i = 0; i <= n; i++) {
487 				if (padLeft) {
488 					if (i < n - strLength)
489 						sb.insert(0, c);
490 				} else {
491 					if (i > strLength)
492 						sb.append(c);
493 				}
494 			}
495 		}
496 		return sb.toString();
497 	}
498 
499 	public static synchronized boolean compare(IMAGE cTImage, IMAGE jTImage) {
500 		if (cTImage == null)
501 			return jTImage == null;
502 
503 		boolean failed = false;
504 
505 		SourceHeader srcHeader = cTImage.getSourceHeader();
506 		if (srcHeader.baseTag != jTImage.getSourceHeader().baseTag) {
507 			System.out.println("<<< mdavid >>> ERROR - Difference in baseTag (arg1/arg2): \"" + srcHeader.baseTag
508 					+ "\" / \"" + jTImage.getSourceHeader().baseTag);
509 			failed = true;
510 		}
511 
512 		if (srcHeader.cameraPortId != jTImage.getSourceHeader().cameraPortId) {
513 			System.out.println("<<< mdavid >>> ERROR - Difference in cameraPortId (arg1/arg2): \""
514 					+ srcHeader.cameraPortId + "\" / \"" + jTImage.getSourceHeader().cameraPortId);
515 			failed = true;
516 		}
517 
518 		if (srcHeader.cameraPortName == null) {
519 			if (jTImage.getSourceHeader().cameraPortName != null) {
520 				System.out.println("<<< mdavid >>> ERROR - Difference in cameraPortName (arg1/arg2): \""
521 						+ srcHeader.cameraPortName + "\" / \"" + jTImage.getSourceHeader().cameraPortName);
522 				failed = true;
523 			}
524 
525 		} else if (!srcHeader.cameraPortName.equals(jTImage.getSourceHeader().cameraPortName)) {
526 			System.out
527 					.println("<<< mdavid >>> WARN - Difference in cameraPortName (arg1/arg2): \""
528 							+ srcHeader.cameraPortName + "\" / \"" + jTImage.getSourceHeader().cameraPortName
529 							+ "\" - IGNORED!");
530 			// res = false;
531 		}
532 
533 		if (srcHeader.versionTag != jTImage.getSourceHeader().versionTag) {
534 			System.out.println("<<< mdavid >>> ERROR - Difference in versionTag (arg1/arg2): \"" + srcHeader.versionTag
535 					+ "\" / \"" + jTImage.getSourceHeader().versionTag);
536 			failed = true;
537 		}
538 
539 		if (srcHeader.totalLength != jTImage.getSourceHeader().totalLength) {
540 			System.out.println("<<< mdavid >>> ERROR - Difference in totalLength (arg1/arg2): \""
541 					+ srcHeader.totalLength + "\" / \"" + jTImage.getSourceHeader().totalLength);
542 			failed = true;
543 		}
544 
545 		if (srcHeader.timestampSeconds != jTImage.getSourceHeader().timestampSeconds) {
546 			System.out.println("<<< mdavid >>> WARN - Difference in timestampSeconds (arg1/arg2): \""
547 					+ srcHeader.timestampSeconds + "\" / \"" + jTImage.getSourceHeader().timestampSeconds
548 					+ "\" - IGNORED!");
549 			// res = false;
550 		}
551 
552 		if (srcHeader.timestampMicroseconds != jTImage.getSourceHeader().timestampMicroseconds) {
553 			System.out.println("<<< mdavid >>> WARN - Difference in timestampMicroseconds (arg1/arg2): \""
554 					+ srcHeader.timestampMicroseconds + "\" / \"" + jTImage.getSourceHeader().timestampMicroseconds
555 					+ "\" - IGNORED!");
556 			// res = false;
557 		}
558 
559 		/* ********************************************************************** */
560 
561 		FrameHeader frameHeader = cTImage.getFrameHeader();
562 		if (frameHeader.sourceWidth != jTImage.getFrameHeader().sourceWidth) {
563 			System.out.println("<<< mdavid >>> ERROR - Difference in sourceWidth (arg1/arg2): \""
564 					+ frameHeader.sourceWidth + "\" / \"" + jTImage.getFrameHeader().sourceWidth);
565 			failed = true;
566 		}
567 
568 		if (frameHeader.sourceHeight != jTImage.getFrameHeader().sourceHeight) {
569 			System.out.println("<<< mdavid >>> ERROR - Difference in sourceHeight (arg1/arg2): \""
570 					+ frameHeader.sourceHeight + "\" / \"" + jTImage.getFrameHeader().sourceHeight);
571 			failed = true;
572 		}
573 
574 		if (frameHeader.aoiWidth != jTImage.getFrameHeader().aoiWidth) {
575 			System.out.println("<<< mdavid >>> ERROR - Difference in aoiWidth (arg1/arg2): \"" + frameHeader.aoiWidth
576 					+ "\" / \"" + jTImage.getFrameHeader().aoiWidth);
577 			failed = true;
578 		}
579 
580 		if (frameHeader.aoiHeight != jTImage.getFrameHeader().aoiHeight) {
581 			System.out.println("<<< mdavid >>> ERROR - Difference in aoiHeight (arg1/arg2): \"" + frameHeader.aoiHeight
582 					+ "\" / \"" + jTImage.getFrameHeader().aoiHeight);
583 			failed = true;
584 		}
585 
586 		if (frameHeader.xStart != jTImage.getFrameHeader().xStart) {
587 			System.out.println("<<< mdavid >>> ERROR - Difference in xStart (arg1/arg2): \"" + frameHeader.xStart
588 					+ "\" / \"" + jTImage.getFrameHeader().xStart);
589 			failed = true;
590 		}
591 		if (frameHeader.yStart != jTImage.getFrameHeader().yStart) {
592 			System.out.println("<<< mdavid >>> ERROR - Difference in yStart (arg1/arg2): \"" + frameHeader.yStart
593 					+ "\" / \"" + jTImage.getFrameHeader().yStart);
594 			failed = true;
595 		}
596 		if (frameHeader.bytesPerPixel != jTImage.getFrameHeader().bytesPerPixel) {
597 			System.out.println("<<< mdavid >>> ERROR - Difference in bytesPerPixel (arg1/arg2): \""
598 					+ frameHeader.bytesPerPixel + "\" / \"" + jTImage.getFrameHeader().bytesPerPixel);
599 			failed = true;
600 		}
601 		if (frameHeader.effectiveBitsPerPixel != jTImage.getFrameHeader().effectiveBitsPerPixel) {
602 			System.out.println("<<< mdavid >>> ERROR - Difference in effectiveBitsPerPixel (arg1/arg2): \""
603 					+ frameHeader.effectiveBitsPerPixel + "\" / \"" + jTImage.getFrameHeader().effectiveBitsPerPixel);
604 			failed = true;
605 		}
606 		if (frameHeader.horizontalBinning != jTImage.getFrameHeader().horizontalBinning) {
607 			System.out.println("<<< mdavid >>> ERROR - Difference in horizontalBinning (arg1/arg2): \""
608 					+ frameHeader.horizontalBinning + "\" / \"" + jTImage.getFrameHeader().horizontalBinning);
609 			failed = true;
610 		}
611 		if (frameHeader.verticalBinning != jTImage.getFrameHeader().verticalBinning) {
612 			System.out.println("<<< mdavid >>> ERROR - Difference in verticalBinning (arg1/arg2): \""
613 					+ frameHeader.verticalBinning + "\" / \"" + jTImage.getFrameHeader().verticalBinning);
614 			failed = true;
615 		}
616 		if (frameHeader.sourceFormat != jTImage.getFrameHeader().sourceFormat) {
617 			System.out.println("<<< mdavid >>> ERROR - Difference in sourceFormat (arg1/arg2): \""
618 					+ frameHeader.sourceFormat + "\" / \"" + jTImage.getFrameHeader().sourceFormat);
619 			failed = true;
620 		}
621 		if (frameHeader.imageFormat != jTImage.getFrameHeader().imageFormat) {
622 			System.out.println("<<< mdavid >>> ERROR - Difference in imageFormat (arg1/arg2): \""
623 					+ frameHeader.imageFormat + "\" / \"" + jTImage.getFrameHeader().imageFormat);
624 			failed = true;
625 		}
626 		if (frameHeader.frameNumber != jTImage.getFrameHeader().frameNumber) {
627 			System.out.println("<<< mdavid >>> ERROR - Difference in frameNumber (arg1/arg2): \""
628 					+ frameHeader.frameNumber + "\" / \"" + jTImage.getFrameHeader().frameNumber);
629 			failed = true;
630 		}
631 		if (frameHeader.eventNumber != jTImage.getFrameHeader().eventNumber) {
632 			System.out.println("<<< mdavid >>> ERROR - Difference in eventNumber (arg1/arg2): \""
633 					+ frameHeader.eventNumber + "\" / \"" + jTImage.getFrameHeader().eventNumber);
634 			failed = true;
635 		}
636 		if (frameHeader.xScale != jTImage.getFrameHeader().xScale) {
637 			System.out.println("<<< mdavid >>> ERROR - Difference in xScale (arg1/arg2): \"" + frameHeader.xScale
638 					+ "\" / \"" + jTImage.getFrameHeader().xScale);
639 			failed = true;
640 		}
641 		if (frameHeader.yScale != jTImage.getFrameHeader().yScale) {
642 			System.out.println("<<< mdavid >>> ERROR - Difference in yScale (arg1/arg2): \"" + frameHeader.yScale
643 					+ "\" / \"" + jTImage.getFrameHeader().yScale);
644 			failed = true;
645 		}
646 		if (frameHeader.imageRotation != jTImage.getFrameHeader().imageRotation) {
647 			System.out.println("<<< mdavid >>> ERROR - Difference in imageRotation (arg1/arg2): \""
648 					+ frameHeader.imageRotation + "\" / \"" + jTImage.getFrameHeader().imageRotation);
649 			failed = true;
650 		}
651 		if (frameHeader.fspare1 != jTImage.getFrameHeader().fspare1) {
652 			System.out.println("<<< mdavid >>> ERROR - Difference in fspare1 (arg1/arg2): \"" + frameHeader.fspare1
653 					+ "\" / \"" + jTImage.getFrameHeader().fspare1);
654 			failed = true;
655 		}
656 		if (frameHeader.fspare2 != jTImage.getFrameHeader().fspare2) {
657 			System.out.println("<<< mdavid >>> ERROR - Difference in fspare2 (arg1/arg2): \"" + frameHeader.fspare2
658 					+ "\" / \"" + jTImage.getFrameHeader().fspare2);
659 			failed = true;
660 		}
661 		if (frameHeader.fspare3 != jTImage.getFrameHeader().fspare3) {
662 			System.out.println("<<< mdavid >>> ERROR - Difference in fspare3 (arg1/arg2): \"" + frameHeader.fspare3
663 					+ "\" / \"" + jTImage.getFrameHeader().fspare3);
664 			failed = true;
665 		}
666 		if (frameHeader.imageFlags != jTImage.getFrameHeader().imageFlags) {
667 			System.out.println("<<< mdavid >>> WARN - Difference in imageFlags (arg1/arg2): \""
668 					+ frameHeader.imageFlags + "\" / \"" + jTImage.getFrameHeader().imageFlags);
669 			// failed = true;
670 		}
671 		if (frameHeader.ispare1 != jTImage.getFrameHeader().ispare1) {
672 			System.out.println("<<< mdavid >>> ERROR - Difference in ispare1 (arg1/arg2): \"" + frameHeader.ispare1
673 					+ "\" / \"" + jTImage.getFrameHeader().ispare1);
674 			failed = true;
675 		}
676 		if (frameHeader.ispare2 != jTImage.getFrameHeader().ispare2) {
677 			System.out.println("<<< mdavid >>> ERROR - Difference in ispare2 (arg1/arg2): \"" + frameHeader.ispare2
678 					+ "\" / \"" + jTImage.getFrameHeader().ispare2);
679 			failed = true;
680 		}
681 		if (frameHeader.ispare3 != jTImage.getFrameHeader().ispare3) {
682 			System.out.println("<<< mdavid >>> ERROR - Difference in ispare3 (arg1/arg2): \"" + frameHeader.ispare3
683 					+ "\" / \"" + jTImage.getFrameHeader().ispare3);
684 			failed = true;
685 		}
686 		if (frameHeader.appendedFrameSize != jTImage.getFrameHeader().appendedFrameSize) {
687 			System.out.println("<<< mdavid >>> ERROR - Difference in fspare3 (arg1/arg2): \""
688 					+ frameHeader.appendedFrameSize + "\" / \"" + jTImage.getFrameHeader().appendedFrameSize);
689 			failed = true;
690 		}
691 
692 		/* ********************************************************************** */
693 		/* ********************************************************************** */
694 		if (cTImage.getSizeInBytes() != jTImage.getSizeInBytes()) {
695 			System.out.println("<<< mdavid >>> WARN - Difference in sizeInBytes (arg1/arg2): \""
696 					+ cTImage.getSizeInBytes() + "\" / \"" + jTImage.getSizeInBytes() + "\" - IGNORED!");
697 			// res = false;
698 		}
699 
700 		String cMD5Hash = TImageMetadata.md5hash(cTImage.getImageFrameBuffer());
701 		String jMD5Hash = TImageMetadata.md5hash(jTImage.getImageFrameBuffer());
702 		if (!cMD5Hash.equals(jMD5Hash)) {
703 			System.out.println("<<< mdavid >>> WARN - Difference in md5hash (arg1/arg2): \"" + cMD5Hash + "\" / \""
704 					+ jMD5Hash);
705 
706 			// failed = true;
707 		}
708 
709 		byte[] buf = Arrays.copyOfRange(cTImage.getImageFrameBuffer(), 0, frameHeader.appendedFrameSize);
710 
711 		boolean b = false;
712 		for (int i = 0; i < buf.length; i++) {
713 			if (buf[i] != jTImage.getImageFrameBuffer()[i] && !b) {
714 				System.out.println("<<< mdavid >>> ERROR - Difference: index = " + i + ", value (arg1/arg2): \""
715 						+ buf[i] + "\" / \"" + jTImage.getImageFrameBuffer()[i] + "\"");
716 				b = true;
717 				failed = true;
718 			}
719 		}
720 
721 		// if (!Arrays.equals(buf, ti2.getImageFrameBuffer())) { // TODO: mdavid
722 		// : why diff ??
723 		// System.out.println("<<< mdavid >>> WARN - Difference in imageFrame buffer");
724 		// res = false;
725 		// }
726 
727 		return !failed;
728 	}
729 
730 	/**
731 	 * Convert 8 bit gray <code>BufferedImage</code> to RGB
732 	 * <code>BufferedImage</code>.
733 	 * 
734 	 * @param image
735 	 *            - source 8 bit gray <code>BufferedImage</code>
736 	 * @return RGB <code>BufferedImage</code>
737 	 */
738 	public static BufferedImage convertGrayByteToRGB(BufferedImage image) {
739 		byte[] byteArray = ((DataBufferByte) image.getRaster().getDataBuffer()).getData();
740 		BufferedImage bi = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_RGB);
741 		int[] intArray = ((DataBufferInt) bi.getRaster().getDataBuffer()).getData();
742 		int numPixels = intArray.length;
743 		for (int i = 0; i < numPixels; i++) {
744 			int gray = byteArray[i] & 0xff;
745 			intArray[i] = 0xff000000 | (gray << 16) | (gray << 8) | (gray);
746 		}
747 		return bi;
748 	}
749 
750 	/**
751 	 * Convert 16 bit gray <code>BufferedImage</code> to RGB
752 	 * <code>BufferedImage</code>.
753 	 * 
754 	 * @param srcImage
755 	 *            - source 16 bit gray <code>BufferedImage</code>
756 	 * @return RGB <code>BufferedImage</code>
757 	 */
758 	public static BufferedImage convertGrayShortToRGB(BufferedImage srcImage) {
759 		int bitsUsed = srcImage.getColorModel().getComponentSize(0);
760 		short[] grayPixels = ((DataBufferUShort) srcImage.getRaster().getDataBuffer()).getData();
761 
762 		BufferedImage bi = new BufferedImage(srcImage.getWidth(), srcImage.getHeight(), BufferedImage.TYPE_INT_RGB);
763 		int[] rgbPixels = ((DataBufferInt) bi.getRaster().getDataBuffer()).getData();
764 		int numPixels = rgbPixels.length;
765 		int shift = bitsUsed - 8;
766 		for (int i = 0; i < numPixels; i++) {
767 			int gray = (grayPixels[i] & 0xffff) >> shift;
768 			rgbPixels[i] = 0xff000000 | ((gray & 0xff) << 16) | ((gray & 0xff) << 8) | (gray);
769 		}
770 		return bi;
771 	}
772 
773 	/**
774 	 * Convert 16 bit gray <code>BufferedImage</code> to 8 bit gray
775 	 * <code>BufferedImage</code>.
776 	 * 
777 	 * @param image
778 	 *            - source 16 bit gray <code>BufferedImage</code>
779 	 * @return RGB <code>BufferedImage</code>
780 	 */
781 	public static BufferedImage convertGrayShortToGrayByte(BufferedImage image) {
782 		if (image == null)
783 			throw new NullPointerException("image == null!");
784 		return new BufferedImage(ColorMap.GRAYSCALE.getLUT(12), image.getRaster(), false, null);
785 	}
786 
787 	/**
788 	 * Converts grayscale image into paletted (indexed) buffered image.
789 	 * 
790 	 * @param srcImage
791 	 *            - grayscale buffered image
792 	 * @param icm
793 	 *            - indexed color model
794 	 * @return - paletted buffered image
795 	 */
796 	public static BufferedImage toIndexedBufferedImage(BufferedImage srcImage, ColorModel icm) {
797 		if (srcImage == null)
798 			throw new NullPointerException("srcImage == null!");
799 		if (icm == null)
800 			throw new NullPointerException("icm == null!");
801 		return new BufferedImage(icm, srcImage.getRaster(), false, null);
802 	}
803 
804 	/**
805 	 * Converts image into colored buffered image.
806 	 * 
807 	 * @param srcImage
808 	 *            - buffered image
809 	 * @return - colored buffered image
810 	 */
811 	public static BufferedImage toColoredBufferedImage(BufferedImage srcImage) {
812 		if (srcImage == null)
813 			throw new NullPointerException("srcImage == null!");
814 
815 		/* create new buffered image with/without alpha */
816 		BufferedImage bi = new BufferedImage(srcImage.getWidth(), srcImage.getHeight(), //
817 				(srcImage.getColorModel().hasAlpha() ? BufferedImage.TYPE_INT_ARGB : BufferedImage.TYPE_INT_RGB));
818 
819 		/* draw image into colored graphics */
820 		((Graphics2D) bi.getGraphics()).drawImage(srcImage, AffineTransform.getRotateInstance(0), null);
821 
822 		/* flushes all image resources */
823 		srcImage.flush();
824 
825 		return bi;
826 	}
827 }