View Javadoc

1   package de.desy.video.sw;
2   
3   import java.io.File;
4   
5   import de.desy.tine.types.*;
6   //file to BufferedImage
7   import java.awt.image.BufferedImage;
8   import java.net.URL;
9   import java.io.IOException;
10  import javax.imageio.ImageIO;
11  import java.net.URISyntaxException;
12  
13  /**
14  * <code>CBasicImageLoaderV3</code> provides loading of any Java SE supported bitmap image 
15  * file format to Video System v3 TINE IMAGE format type. While loading, conversion to 
16  * grayscale image data can be done if desired. Main interest for current usage is PNG file loading from disk.<br>
17  * <br>
18  * The loadable formats are (according to tests using {@link printLoadableFormats()}):
19  * <ul>
20  * <li>BMP
21  * <li>bmp
22  * <li>jpg
23  * <li>JPG
24  * <li>wbmp
25  * <li>jpeg
26  * <li>png
27  * <li>PNG
28  * <li>JPEG
29  * <li>WBMP
30  * <li>GIF
31  * <li>gif 
32  * </ul>
33  * Please note that upper- and lowercase file extensions are outlined, which I think could 
34  * mean that case sensitivity of file extention plays a role and (possibly, unchecked) .PnG
35  * file extension is rejected. 
36  *    
37  * @author <a href="mailto:stefan.weisse@desy.de">Stefan Weisse</a>
38  * @version $Id: Templates.xml,v 1.10 2008/06/20 16:00:13 sweisse Exp $
39  *
40  */
41  public final class CBasicImageLoaderV3 {
42  
43  	/**
44  	 * prints all formats that Java ImageIO class is able to read to stdout. This helps
45  	 * when getting to know which file formats are supported.
46  	 */
47  	public static final void printLoadableFormats() {
48  		String[] names = ImageIO.getReaderFormatNames();
49  		for ( String name: names )
50  		{
51  			System.out.println( name );
52  		}
53  	}
54  
55  	// e.g. file put in JAR file, ...
56  	/**
57  	 * loads an image file with a give filename out of a resource bundle (e.g. JAR file)
58  	 * and puts its contents to TINE IMAGE data type
59  	 * <br>
60  	 * <br>
61  	 * <b>This method is untested!</b>
62  	 * <br>
63  	 * @param aFileName file name (may include relative resource path)
64  	 * @param aOutImage TINE IMAGE data type to put image contents to
65  	 * @param @param aChangeToGrey	if true, image data is downscaled to grayscale before returned
66  	 * @return true - image contents were successfully put into aOutImage<br>
67  	 *         false - some error (aOutImage is null, IOException, URISyntaxException, img.getRGB error)
68  	 */
69  
70  	public static final boolean loadImageResource( String aFileName, IMAGE aOutImage, boolean aChangeToGrey)
71  	{
72  		if (aOutImage == null) return false;
73  		
74  		// (1) load file into java buffered image
75  		BufferedImage img = null;
76  		File imgFile = null;
77  		try {
78  			URL fileURL = Thread.currentThread().getContextClassLoader().getResource(aFileName);
79  			 imgFile = new File( fileURL.toURI() );
80  			img = ImageIO.read( fileURL );
81  		}
82  		catch(IOException ex)
83  		{
84  			return false;
85  		}
86  		catch(URISyntaxException ex)
87  		{
88  			return false;
89  		}
90  		
91  		return postProcess(imgFile, img, aOutImage, aChangeToGrey);
92  	}
93  
94  	/**
95  	 * convenience overload, defaults grayscale conversion to false
96  	 * 
97  	 * @see loadImageFile( String, IMAGE, boolean )
98  	 */ 
99  	
100 	public static final boolean loadImageFile( String aFileName, IMAGE aOutImage)
101 	{
102 		return loadImageFile( aFileName, aOutImage, false);
103 	}
104 	
105 	// purpose: load in known fileformats from disk
106 	// at the moment, png, jpeg, gif, ... are supported directly by java image loading functions
107 	/**
108 	 * loads an image file with a give filename from disk
109 	 * and puts its contents to TINE IMAGE data type
110 	 * <br>
111 	 * @param aFileName file name (may include path)
112 	 * @param aOutImage TINE IMAGE data type to put image contents to
113 	 * @param aChangeToGrey	if true, image data is downscaled to grayscale before returned
114 	 * @return true - image contents were successfully put into aOutImage<br>
115 	 * 		   false - some error (aOutImage is null, IOException, URISyntaxException, error img.getRGB)
116 	 */
117 	public static final boolean loadImageFile( String aFileName, IMAGE aOutImage, boolean aChangeToGrey)
118 	{
119 		if (aOutImage == null) return false;
120 		
121 		// (1) load file into java buffered image
122 		BufferedImage img = null;
123 		File imgFile = null;
124 		try {
125 			imgFile = new File( aFileName );
126 			img = ImageIO.read( imgFile );
127 		}
128 		catch(IOException ex)
129 		{
130 			return false;
131 		}
132 		
133 		return postProcess(imgFile, img, aOutImage, aChangeToGrey);
134 	}
135 	
136 	/* no javadoc
137 	 * 
138 	 * postprocesses the java buffered image and creates a VSv3 transport layer compatible image
139 	 * out of it, color-to-grayscale can be performed in this step on demand, File class is 
140 	 * necessary for file name string only
141 	 * 
142 	 * returns false in the following cases
143 	 *	  img.getRGB error
144 	 */
145 	private static final boolean postProcess(File imgFile, BufferedImage img, IMAGE aOutImage, boolean aChangeToGrey)
146 	{
147 		// (1) obtain TYPE_INT_ARGB pixel array out of "img"
148 		
149 		int imgWidth = img.getWidth();
150 		int imgHeight = img.getHeight();
151 		
152 		int[] pixelArr = new int[imgWidth*imgHeight];
153 				
154 		if (img.getRGB(0,0,imgWidth, imgHeight, pixelArr, 0, imgWidth) == null)
155 			return false;
156 
157 		// (2) create TINE IMAGE type out of it
158 		
159 		IMAGE.FrameHeader frameHeader = aOutImage.getFrameHeader();
160 		IMAGE.SourceHeader sourceHeader = aOutImage.getSourceHeader();
161 
162 		if (aChangeToGrey == true) {
163 			frameHeader.bytesPerPixel = 1;
164 			frameHeader.effectiveBitsPerPixel = 8;
165 			frameHeader.imageFormat = (int) CVideoHeader3.CF_IMAGE_FORMAT_GRAY;
166 			frameHeader.sourceFormat = (int) CVideoHeader3.CF_IMAGE_FORMAT_GRAY;
167 		}
168 		else
169 		{
170 			// keep RGB
171 			frameHeader.bytesPerPixel = 3;
172 			frameHeader.effectiveBitsPerPixel = 24;
173 			frameHeader.imageFormat = (int) CVideoHeader3.CF_IMAGE_FORMAT_RGB;
174 			frameHeader.sourceFormat = (int) CVideoHeader3.CF_IMAGE_FORMAT_RGB;
175 		}
176 	
177 
178 		frameHeader.appendedFrameSize = imgWidth*imgHeight*frameHeader.bytesPerPixel;
179 		
180 		frameHeader.aoiHeight = -1;
181 		frameHeader.aoiWidth = -1;
182 
183 		frameHeader.eventNumber = 0;
184 		frameHeader.frameNumber = 0;
185 		frameHeader.fspare1 = (float) -1.0;
186 		frameHeader.fspare2 = (float) -1.0;
187 		frameHeader.fspare3 = (float) -1.0;
188 		frameHeader.horizontalBinning = 0;
189 		frameHeader.imageFlags = (int) CVideoHeader3.CF_IMAGE_FLAG_IMAGE_LOSSLESS | (int) CVideoHeader3.CF_IMAGE_FLAG_LITTLE_ENDIAN_BYTE_ORDER;
190 		
191 		frameHeader.imageRotation = (float) 0.0;
192 		frameHeader.ispare1 = -1;
193 		frameHeader.ispare2 = -1;
194 		frameHeader.ispare3 = -1;
195 		frameHeader.sourceHeight = imgHeight;
196 		frameHeader.sourceWidth = imgWidth;
197 		frameHeader.verticalBinning = 0;
198 		frameHeader.xScale = (float) 1.000;
199 		frameHeader.xStart = 0;
200 		frameHeader.yScale = (float) 1.000;
201 		frameHeader.yStart = 0;
202 		
203 		sourceHeader.baseTag = (int) CVideoHeader3.CF_IMAGE_MAGIC_01;
204 		sourceHeader.cameraPortName = "file://"+imgFile.getName(); // TODO: could be too long and truncated badly
205 		sourceHeader.cameraPortId = (int) CVideoHeader3.CF_IMAGE_NO_CAMERA_PORT_ID;
206 
207 		long msTimeEpoch = imgFile.lastModified();
208 		sourceHeader.timestampMicroseconds = (int) (((msTimeEpoch%((long)1000))*((long)1000)));
209 		sourceHeader.timestampSeconds = (int) (((msTimeEpoch)/((long)1000)));
210 
211 		sourceHeader.totalLength = CVideoHeader3.HDRSIZE + frameHeader.appendedFrameSize;
212 		sourceHeader.versionTag = CVideoHeader3.CF_IMAGE_VERSION;
213 		
214 		byte[] buf = new byte[frameHeader.appendedFrameSize];
215 
216 		// imperformant, but fast-to-implement solution:
217 		// Note: maybe make faster!
218 		
219 		if (aChangeToGrey == true)
220 		{
221 			for (int i=0;i<frameHeader.sourceWidth*frameHeader.sourceHeight;i++)
222 			{
223 				double r = (double) ((pixelArr[i]>>16)&0xff);
224 				double g = (double) ((pixelArr[i]>>8)&0xff);
225 				double b = (double) (pixelArr[i]&0xff);
226 				buf[i] = (byte) (0.114*b+0.587*g+0.299*r);
227 			}
228 		}
229 		else
230 		{
231 			int pos = 0;
232 			for (int i=0;i<frameHeader.sourceWidth*frameHeader.sourceHeight;i++)
233 			{
234 				buf[pos++] = (byte) ((pixelArr[i]>>16)&0xff); // R
235 				buf[pos++] = (byte) ((pixelArr[i]>>8)&0xff); // G
236 				buf[pos++] = (byte) (pixelArr[i]&0xff); // B
237 			}
238 		}
239 
240 		aOutImage.setImageFrameBuffer(buf);
241 				
242 		return true;
243 	}
244 }