Applet Problem - stockende und springende Bilderabfolge

Status
Nicht offen für weitere Antworten.

Loki

Aktives Mitglied
Hallo,
ich habe eine Bildsequenz gegeben, die ich über ein Applet erst einmal ausgeben möchte. Siehe Code.
Mein Problem ist, das die Abfolge nicht so wiedergegeben wird, wie das im Bildmaterial aufgezeichnet wurden ist. D.h. es gibt Sprünge in der Sequenz. Meine Vermutung ist das es an der Pufferung bzw. Ausgabe liegt. Wie kann ich das umgehen. Man beachte das die Sequenzfolge relativ groß ist und einiges an Speicher beansprucht.

File-Upload.net - err.FLV

Java:
import java.applet.Applet;
import java.awt.*;

public class firstApplet extends Applet implements Runnable {
	int	current  = 0;
	int	size=400;

	public void update(Graphics g) {
		// Don't repaint background, it only slow applet down
	    paint(g);
	}

	public void paint (Graphics g) {
		String strNumber;

		//synchronized(this) {
		strNumber = Integer.toString(++current);
		while(strNumber.length() != 4) 
				strNumber= new String('0'+strNumber);
		g.drawImage(getImage(getDocumentBase(),"m_hain_005_b4150_1_8gl_getr_3rast_"+strNumber+".JPG"), 0, 0, this);
		if (current == size) 
			current=0;
		//}
		
	}

	public void run() {
		
			
		try {
			for (;;) {
				// Repaint the images
				repaint();
				Thread.sleep(50);
			}								
		} catch(InterruptedException e) {}
	}
}

Der Code ist ein biss. zusammengefrickelt aus einer anderen Lösung.
 
Zuletzt bearbeitet:
Ich habe mal eine Variante mit dem MediaTracker gebaut, leider kommt man dort schnell ans Speicherlimit eines Applet. Dort spielt er aber alles in der richtigen Reihenfolge ab.
[Java]
import java.applet.Applet;
import java.awt.*;

public class SecondApplet extends Applet implements Runnable {
Image[] imgArray = null;
MediaTracker tracker = null;
int current = 0;
Thread animThread=null;
int SIZE=40;

public void init() {
String strNumber;

if (tracker == null) {
// Create a new media tracker, to track loading images
tracker = new MediaTracker(this);

// Create an array of three images
imgArray = new Image[SIZE];
// Start downloading the images
for (int index=0; index < SIZE; index++) {
strNumber=Integer.toString(index+1);
// Load the image
while(strNumber.length() != 4)
strNumber= "0"+strNumber;

imgArray[index] = getImage(getDocumentBase(),"ressources//m_hain_005_b4150_1_8gl_getr_3rast_"+strNumber+".JPG");

// Register it with media tracker
tracker.addImage(imgArray[index], index);
//tracker.addImage(getImage( getDocumentBase(),"m_hain_005_b4150_1_8gl_getr_3rast_"+strNumber+".JPG") , index);
}

// Start animation thread
animThread = new Thread(this);
animThread.start();
}
}

public void update(Graphics g) {
// Don't repaint background, it only slow applet down
paint(g);
}

public void paint (Graphics g) {

// Check to see if images have started loading
if (tracker == null) {
g.drawString ("Click",20,20);
}
else
// Check to see if images have loaded
if (tracker.checkAll()) {
g.drawImage(imgArray[current++], 0, 0, this);

if (current >= SIZE)
current=0;
}
else
// Still loading{
g.drawString ("Images are loading...", 20,20);

}

public void run() {
try {
tracker.waitForAll();
for (;😉 {
// Repaint the images
repaint();
Thread.sleep(50);
}
}
catch (InterruptedException ie) {};
}
}[/Java]
 
kleiner Bugfix

Java:
Image ressource=getImage(getDocumentBase(),"ressources//m_hain_005_b4150_1_8gl_getr_3rast_"+strNumber+".JPG");
		while(!g.drawImage(ressource, 0, 0, this)); 
		ressource=null;
		
		if (current++ >= size-1) 
			current=0;
 
/*Wenn du die Bilder einmal irgendwo in "init()" statt immer wieder in "paint()" laden würdest, hättest du einen entscheidenden Vorteil.*/
@Edit: 😳 ist ja schon geschehen... Bin noch nicht wirklich wach heut' morgen 🙂
 
Zuletzt bearbeitet von einem Moderator:
Also die einfachsten lösungen die mir so in den sinn kommen wären
Umsteigen auf Swing statt AWT weil da bereits automatisch doppelt gebuffered wird
Java:
import javax.swing.JApplet;   //<---
import java.awt.*;

public class SecondApplet extends JApplet /*<---*/ implements Runnable 
{
      /*
       *krimskrams
       */
}

ansonsten müssteste mal nach double buffering schaun... da weiß ich au nix von weil ich swing nehme

un was evtl auch helfen könnte wäre ein repaint das nur bestimmte stellen repainted
Java:
repaint(x, y, width, heigth); //glaub ich zumindest
Siehe hier, da steht auch was zum double buffering zwischen
 
Zuletzt bearbeitet:
Ist beim simplen Anzeigen von Bildfolgen DubleBuffering überhaupt nötig? Wenn's hier nur um den Speicher geht, wäre es vllt. sinnvoll, wenn man einen zusätzlichen Thread erstellt, der nur einen Teil der Bildfolge in einer Queue cached aus welcher sie, nach dem sie angezeigt wurden, wieder entfernt werden müssten. Natürlich muss dann auch gewährleistet sein, das der Ladethread die Bilder schneller lädt als das sie vom Repaintthread angezeigt würden. Das würde ich dann mit "wait()" und "notify()" realisieren.
Obwohl hier völlig unnötig... DubleBuffering in AWT:
Java:
public void paint(Graphics g)
{
  // buf ist normalerweise eine Instanzvariable und braucht nur erstellt werden, wenn es
  // noch nicht erstellt wurde oder sich die Grösse der Component verändert hat.
  BufferedImage buf = new BufferedImage(getWidth(), getHeight(), BufferedImage.TRANSLUCENT);
  Graphics g2 = buf.getGraphics();
  // in den GraphicsContext g2 zeichnen
  ...
  // buf in den GraphicsContext der Component zeichnen
  g.drawImage(buf,0,0,null);
}
 
Zuletzt bearbeitet von einem Moderator:
Du bringst mich grade auf ne idee... leider weiß ich nich ob bzw wie das in Java ginge da ich das ganze nur in C# gemacht hab...

das ganze hat im prinzip ein string array mit allen pfaden der einzelnen dateien gemacht un hat zufällig die einzelnen indexe angesteuert un verarbeitet...

edit:
So, geschaut, gebastelt...

Java:
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.image.ImageObserver;
import java.io.File;
import java.util.*;

import javax.imageio.ImageIO;



public class Something
{
	int count = 0;
	ArrayList<Image> imges = new ArrayList<Image>();
	
	public void someMethod()
	{
		ArrayList<Image> img = new ArrayList<Image>();
		File dir = new File("PFAD");		
		File[] fileList = dir.listFiles();		
		for(File f : fileList) 
		{
			try
			{
				Image itsAnImage = ImageIO.read(f);
				img.add(itsAnImage);
			}
			catch(Exception e)
			{
				e.printStackTrace();
			}
		}
		this.imges = img;
	}
	
	public void paint(Graphics g)
	{
		g.drawImage(imges.get(count),0,0,(ImageObserver) this);
		if(count < imges.size())
		{
		count++;
		}
		else
		{
			/*
			 * Das musste selbst wissen... 
			 */ 
		}
	}
}

und nun mal zum lesen...

wir nehmen uns das directory als file,
holen daraus die ganzen files (Fußnote 1)
bauen uns ein image daraus
packen es in die arraylist
den ganzen zauber haben wir damit fertig, nu springste einfach im paint den jeweiligen index durch (dafür der count)

Damit sollten zumindest sprünge verhindert sein, falls des no flackert wirds wohl auf einen der beiden beiträge hier drüber raus laufen.

Außerdem wird einiges an speicher reduziert weil nicht jedes bild immer vorhanden ist sondern immer nur das nötige geladen wird, geht allerdings zu lasten der geschwindigkeit aber das dürfte kein großes problem werdn

Ich hoffe das hilft wenigstens etwas 😳


Fußnote 1:
gibt auch die möglichkeit filter rein zu setzn, so das du nur bilder bekommst, den code weiß ich aber so auch nich.
 
Zuletzt bearbeitet:
Das Problem war von Anfang an das Laden der Bilder. Leider habe ich mehrmals den Rückgabewert von drawImage "überlesen", naja nun klappt die eine Variante. Ist aber mit flackern verbunden und nicht besonders schnell.
Die Mediatracker Variante, die funktioniert noch nicht. Ich schätze mal, dass der Speicher voll ist bei mehr als 40 Einzelbildern im Mediatracker.
Für meine Animation eindeutig zu wenig. Evtl. würde das mit 2 parallelen mediatracker besser funktionieren, die sich abwechseln.

@Odin: Bin mir nicht unbedingt sicher, ob das immer so funktioniert. Wird das denn alphabetisch geordnet?
 
Zuletzt bearbeitet:
Ja, es liest alphabetisch - mitsamt Thumbs.db file etc. un bei ordnern muckts, ich such glei ma den filterkrempel

Ob es hilft wirst du mir wohl mal sagn müssen... ich kenn den mediatracker nich un musst kürzlich erst lernen das ImageIO ne tolle sache is, darum gewöhn ich mir das an.

is halt wie gesagt der gedanke das du bei jedem bildwechsel X ms wartest um eben ein einzelnes bild zu laden un nich XXXXXX byte für alle geladenen bilder


Filter gefunden:
Java:
		File[] fileList = dir.listFiles(new FilenameFilter()
		{
			public boolean accept(File d, String name)
			{
				boolean ret = false;
				if(name.endsWith(".jpg") || name.endsWith(".gif"))
				{
					ret = true;
				}
				return ret;
			}
		});
 
Was mich wundert ist das das Andere besser hinbekommen haben. Z.B. der da DMG-Lib: Stöbern, Interaktive Animationen

Es scheint also noch eine bessere Lösung zu geben.

Java:
import javax.swing.JApplet;
import java.awt.*;
import java.awt.image.*;

public class FirstApplet extends JApplet{
	int	current  = 0;
	int	size=400;
	boolean bool=false;
	
	public void update(Graphics g) {
		paint(g);
	}

	public void paint (Graphics g) {
		String strNumber=Integer.toString(current+1);
		
		while(strNumber.length() != 4) 
			strNumber= "0"+strNumber;
		
		Image ressource=getImage(getDocumentBase(),"ressources//m_hain_005_b4150_1_8gl_getr_3rast_"+strNumber+".JPG");
		prepareImage(ressource, this);
		while ((checkImage(ressource, this) & ALLBITS)!=ALLBITS);
		g.drawImage(ressource, 0, 0, this);

		
		
		if (current++ >= size-1) 
			current=0;
		
	}

	public void start() {
			
			while(true)  
				repaint();
	}
}
 
Die Animation lädt und hält die Bilder im Speicher. Grad so, wie du mit deiner MediaTracker Version. Ist zwar performant aber nicht unbedingt speicherfreundlich. Bei JPG, PNG und vorallem bei BMP dürfte die im Beispiel verwendete Grösse der Bilder schon nahe an die obere Grenze des standardmässig verfügbaren Speichers stossen. Eine Weitere Möglichkeit wäre, das die Grafiken aus einzelnen Teilen (einzelne Hebelelemente und Hintergrund) mit Formeln für Hebelgesetze berechnet oder per SVG definiert werden. Für letzteres sollte man sich mal Batik ansehen.
 
Ich werde mal schauen, ob ich Kontakt zum Entwickler bekomme. Auch bei meiner Version mit MediaTracker und BMP scheitert es schon bei 40 geladenen Bildern im Applet. Und die Speicherbegrenzung vom Applet sind doch nicht so einfach behebbar.
 
Vllt. genügt es ja schon, statt BMP PNG zu verwenden. Das Format ist doch nur beim laden der Bildfolge entscheidend. PNG ist kompimiert und verbraucht beim laden deswegen weniger Ressourcen. Letzendlich landen die Bilder doch ohnehin in Bildobjekten mit 32 Bit Farbtiefe pro Pixel.
Apropos: Der Mindestspeicherverbrauch lässt sich ja berechnen.
Code:
Länge(px) * Breite(px)*Farbtiefe(bit)/8=Speicherverbrauch(Bytes)
So wie du die Bilder mit dem Mediatracker lädst, benötigst du im Zewifelsfall von dem errechneten das doppelte, da die Bilder parallel geladen werden. Versuch also auch mal die Bilder hintereinander zu laden:
Java:
MediaTracker mt = new MediaTracker((Component) this);
ArrayList<Image> anim = new ArrayList<Image>();
Image img = null;
for(int i = 0; i < anzBilder; i++) {
  img = getImage(getDocumentBase(),"ressources//m_hain_005_b4150_1_8gl_getr_3rast_"+(i+1)+".JPG");
  mt.addImage(img, 0)
  try {
    mt.waitFor(0);
  } catch(InterruptedException e) {
    // nothing
  }
  anim.add(img);
}
 
Zuletzt bearbeitet von einem Moderator:
Status
Nicht offen für weitere Antworten.

Neue Themen


Zurück
Oben