# Wie mache ich einen Screenshot vom Display (LWJGL)?



## Friedhelm (16. Aug 2010)

Ich habe nur alte Sachen von 2004 gefunden... mit endlosen Codezeilen.

Ich glaube mich aber daran zuerrinnern, dass ich irgendwoe einen Befehl dafür gesehen habe, mit dem man ins Ram oder direkt in ein File capturen kann.

Trügt hier mein Gedächtnis?


Ich möchte daraus dann ein Movie machen.


----------



## Friedhelm (16. Aug 2010)

Also ich habs jetzt so gemacht:


[Java]

private void saveFrameAsPNG(String fileName ) {

		// Open File
		if( fileName == null ) {

			fileName = new String( "Screenshot.png" ); 
		}

		File outputFile = new File( fileName );				

		try {
			javax.imageio.ImageIO.write( takeScreenshot(), "PNG", outputFile );

		} catch (Exception e) {
			System.out.println( "Error: ImageIO.write." );
			e.printStackTrace();
		}
	}


	private BufferedImage takeScreenshot(){

		int frameWidth = Display.getDisplayMode().getWidth();
		int frameHeight = Display.getDisplayMode().getHeight();

	    BufferedImage screenshot = null;
	     // allocate space for RBG pixels
	    ByteBuffer fb = ByteBuffer.allocateDirect(frameWidth*frameHeight*3);	

	     int[] pixels = new int[frameWidth * frameHeight];
	     int bindex;

	     // grab a copy of the current frame contents as RGB
	     GL11.glReadPixels(0, 0, frameWidth, frameHeight, GL11.GL_RGB, GL11.GL_UNSIGNED_BYTE, fb);


	     // convert RGB data in ByteBuffer to integer array
	     for (int i=0; i < pixels.length; i++) {
	         bindex = i * 3;
	         pixels_ = ((fb.get(bindex) << 16))  + ((fb.get(bindex+1) << 8))  + ((fb.get(bindex+2) << 0));
	     }

	     // Create a BufferedImage with the RGB pixels then save as PNG
	     try {
	         screenshot = new BufferedImage(frameWidth, frameHeight, BufferedImage.TYPE_INT_RGB);
	         screenshot.setRGB(0, 0, frameWidth, frameHeight, pixels, 0, frameWidth);	  


	         // * Flip Image Y Axis *
	         AffineTransform tx = AffineTransform.getScaleInstance(1, -1); 
	         tx.translate(0, -screenshot.getHeight(null)); 
	         AffineTransformOp op = new AffineTransformOp(tx, AffineTransformOp.TYPE_NEAREST_NEIGHBOR); 
	         screenshot = op.filter(screenshot, null); 

	     }
	     catch (Exception e) {
	         System.out.println("ScreenShot() exception: " +e);
	     }
	     return screenshot;
	}


[/Java]

Nicht schön... aber selten. Jedenfalls bekomme ich in iMove damit smooth 30FPS. Damit bin ich mehr als zufrieden. Übrigens ist da noch ein Bug, wenn man die Hintergrund Farbe von Display auf (0,1,0) stellt (also schön helles Greenscreen Grün), dann speichert er das Grün als Gelb. Erst wenn man (0.1,1,0.1) verwendet, dann speichert er das Grün als Grün. Weiß jemand warum?

Weiß jemand wie ich die Bilder zu einem Mov zusammensetze (evt. mit Quicktime for Java, oder besser noch nativ irgendwie)? Denn bisher muss ich die Einzelbilder in iPhoto laden, dann in iMovie, und in iMovie als Film exportieren (Apple Intermediate), dann wieder zur weiteren Greenscreen Anwendung nochmals als Film einladen. Naja, etwas umständlich :lol:_


----------



## Marco13 (16. Aug 2010)

Eine MOV rausschreiben geht pratkischerweise relativ leicht mit dem Beispiel vom Java Media Framework: jpegimagestomovie - Google Search (Google-Link - der original-Link verwies auf eine Sun-Seite, und ... tja  ).

Man kann das mit relativ geringem Aufwand so umbiegen, dass die DataSource keine JPG-Datei mehr ist, sondern nur ein Buffer, in dem die Bilddaten direkt liegen.


----------



## Friedhelm (16. Aug 2010)

Ja, ich suche schon seit ca. 6 Stunden wie das in Java funktioniert.

Das JMF (JpegImagesToMovie) kann ich nicht für Mac downloaden, das gibt es nur für Linux und Windows.

Ich habe schon zig vermeintliche Lösungen probiert:

- FMJ
- FFMpegJ
- ... 
- und noch 4 andere die mir nicht mehr einfallen.


Tja, das größte Problem scheinen die native Files für mac zu sein. Viele Projekte für Java endeten 2003,2004 und 2007. 

Ehrlich gesagt bin ich etwas ratlos.


Ich brauche eine Lösung mit native Mac Files, oder eine only Java Lösung, weil ich nicht extra ein Zusatzpaket installieren will, die "um die Ecke" Linux Packets für Mac zum laufen bringen ueh:

Hat jemand noch einen Vorschlag?


----------



## Friedhelm (16. Aug 2010)

So, ich habe mich eben nochmal 2 Stunden mit GStreamer rumgeschlagen. Aber das geht nur wenn man MacPorts benutzt, ein paar Scripte auf batch Ebene editiert und ein 108 MB GStreamer Paket installiert (Computer Neustart erforderlich).

Ergebnis: geht trotzdem nicht. Ist auch viel zu umständlich. Wenn ich es als Programmierer schon nicht hinbekomme, kann man das ja wohl anderen Usern erst recht nicht zumuten, nur damit sie Dein Programm nutzen können.

Ich denke ich lass das erstmal und arbeite an anderen Baustellen, dass ist denke ich sinnvoller anstatt sich tagelang mit etwas zu beschäftigen, was offensichtlich nicht für Mac und Java funktioniert.


----------



## Evil-Devil (17. Aug 2010)

Hab hier noch alten Code...der den aktuellen Frame nimmt und als TGA speichert.


```
public final void takeScreenShot() {
	ByteBuffer screenData = BufferUtils.createByteBuffer(width*height*3);

	GL11.glReadPixels(0,0,(int)width,(int)height,GL11.GL_RGB,GL11.GL_UNSIGNED_BYTE,screenData);
	// swap the r and g values
	ByteBuffer swapedScreenData = BufferUtils.createByteBuffer(width*height*3);
	for (int i=0; i<swapedScreenData.capacity(); i+=3) {
		final byte red = screenData.get();
		final byte blue = screenData.get();
		final byte green = screenData.get();
		swapedScreenData.put(green);     // G
		swapedScreenData.put(blue);     // B
		swapedScreenData.put(red);     // R
	}
	swapedScreenData.flip();
	writeScreenShot(swapedScreenData);
}

private void writeScreenShot(ByteBuffer data) {
	byte[] tgaHeader = new byte[] { 0,0,2,0,0,0,0,0,0,0,0,0 };        
	final Date date = new Date();
	File screenFile = new File("Screenshot_"+date.getDate()+date.getMonth()+date.getYear()+"_"+date.getHours()+date.getMinutes()+".tga");
	try {
		FileOutputStream fos = new FileOutputStream(screenFile);
		DataOutputStream dos = new DataOutputStream(fos);
		// write the header
		fos.write(tgaHeader);
		dos.write(128);
		dos.write(2);
		dos.write(224);
		dos.write(1);
		dos.write(24);
		dos.write(0);
		// write the image data
		fos.getChannel().write(data);           
		fos.close();
	} catch (FileNotFoundException fnfe) {
		fnfe.printStackTrace();
	} catch (IOException ioe) {
		ioe.printStackTrace();
	}

}
```

Die Aufrufe von BufferUtils sind lediglich Wrapper auf den LWJGLBuffer Util Methoden. Um also einen ByteBuffer der benötigten Größe zu erzeugen, kannst du direkt auf die LWJGL BufferUtil Methoden zurückgreifen und im Beispiel entsprechend einfügen. 

Der Code ist nicht sonderlich effektiv, aber er reichte damals aus ^^"


----------



## Kr0e (18. Aug 2010)

Xuggler kann von allen lösungen am einfachsten und besten aus Bildern Videos zusammen schnibbeln und das in jedem format und auf jeder plattform. Fix und fertig mit Installer. Kinderleicht


----------



## Evil-Devil (18. Aug 2010)

Kr0e hat gesagt.:


> Xuggler kann von allen lösungen am einfachsten und besten aus Bildern Videos zusammen schnibbeln und das in jedem format und auf jeder plattform. Fix und fertig mit Installer. Kinderleicht



Damit kannst aber keinen Screenshot aus einer LWJGL Applikation erzeugen, sondern nur den produzierten Screenshot nutzen.


----------

