# Performance Problem bei BufferedImage



## MaZeFrJoTh (6. Jul 2011)

Hallo liebe Leute ich habe nun mein erstes 2D Spiel fast fertig. Dies läuft soweit sehr flüssig, jedoch ist meine Prozessorauslastung bei 80% und bei alten PCs braucht es 40sec bis der Hintergrund aufgebaut wird. Ich verwende bisher png und für den Hintergrund jpg. Diese werden dann als BuffererdImage gespeichert und über die paintComponent Methode gezeichnet. Liegt dieser krasse Performance Unterschied daran, dass die alten PCs vllt nicht die neuste Java Version haben und somit auch keine Hardwarebeschleunigung. Ich zeig euch mal meine Methoden die ich benötige, um die Bilder zeichnen zu können:


```
private BufferedImage[] LadeBilder(String Pfad, int Bilder){        
            BufferedImage[] animation = new BufferedImage[Bilder];
            BufferedImage source = null;        
            URL Hole_url = getClass().getClassLoader().getResource(Pfad);
            try {
                source = ImageIO.read(Hole_url);
            }
            catch (IOException e){}        
            for(int i = 0;i < Bilder;i++){
                animation[i] = source.getSubimage(i*source.getWidth()/Bilder, 0, source.getWidth()/Bilder, source.getHeight());
            }           
            return animation;
        }
```

und:


```
public void paintComponent(Graphics g){ 
            super.paintComponent(g);
            g.drawImage(Hintergrund, 0, 0, this);
            g.drawImage(Korb, o, 710,this);
            for(int i = 1; i <= 43; i++){
                g.drawImage(Apfel, koords[i].x, koords[i].y, this);
            }
            g.setColor(Color.red);
            g.setFont(new Font("Arial", Font.PLAIN, 30));
            g.drawString("Punkte: " + Long.toString(punkte), 530, 35);
            g.drawString("Zeit: " + Long.toString(30 - timer.Zeit()), 15, 35);
        }
```

Und ist BufferedImage hier schon angebracht oder wäre hier ManagedImage oder VolatileImage die bessere Wahl?

Danke an alle die mir helfen können.


----------



## Kr0e (6. Jul 2011)

Also solang du die Bilder nur EINMAL lädst (Und das tust du ja hoffentlcih ) und dann einfahc nur die referenzen zeichnest, sollte es da überhaupt kein Problem geben...

Vlt mal einen Profiler drüber laufen lassen. Bei Netbeans bereits integriert


----------



## MaZeFrJoTh (6. Jul 2011)

Ich glaub schon, dass ich das Bild nur einmal Lade aber das geht auch SEEHR langsam. Und was heist nur die Referenzen zeichnen. Das Programm Netbeans ist mir auch nicht bekannt.


----------



## Kr0e (6. Jul 2011)

Also Netbeans ist ne IDE so wie Eclipse, die manchen arbeiten damit lieber, ich hingegen mit Netbeans^^ Ist Geschmacksache. Aber ich weiß halt, dass bei Netbeans ein Profiler drin ist, keine Ahnung ob das bei Eclipe auch der Fall ist, denke aber mal schon....

Mit "Referenzen zeichnen" hab ich mich vlt doof ausgedrückt, was ich meine ist:

Du lädst alle Bilder/Resourcen am Anfang des Programms und hinterher zeichnest du diese bereits geladenen Bilder... Also nicht, dass die bilder hinterher in jedem Durchgang neugeladen werden...


----------



## Apo (6. Jul 2011)

Gleiches Problem hatte ich ja auch siehe da und was mir davon vor allem geholfen hat war das

Ich habe mir geholfen indem ich ein neues Bild erstellt habe und das geladene einfach reingemalt habe. Hat bei mir sehr viel gebracht. Natürlich musst du auch drauf achten was Kr0e gesagt hat.


```
private static BufferedImage getImage(BufferedImage iOriginal, boolean transparent) {
	int type = iOriginal.getType();
	if (transparent) {
		type = BufferedImage.TYPE_INT_ARGB_PRE;
	} else {
		type = BufferedImage.TYPE_INT_RGB;				
	}
	BufferedImage iNew;
	try {
		iNew = new BufferedImage(iOriginal.getWidth(), iOriginal.getHeight(), type);
	} catch (Exception ex) {
		iNew = new BufferedImage(iOriginal.getWidth(), iOriginal.getHeight(), BufferedImage.TYPE_INT_RGB);
	}
	if (iNew != null) {
		Graphics2D g = iNew.createGraphics();
		g.drawImage(iOriginal, 0, 0, null);
		g.dispose();
	}
	return iNew;
}
```


----------



## Kr0e (6. Jul 2011)

@Apo:

Das Problem hatte ich auch mal, als ich Swing auf ein BufferedImage gezeichnet hab. Hab mich immer gewundert, wo der enorme Performanceverlust herkommt. Falsche Buffertypen können einem da ganz schön ins Handwerk fuschen... Guter Hinweis!


----------



## twseitex (6. Jul 2011)

Hallo, ein Auszug aus meinem Java-Audioplayer auf audio, flash and java

 Die Kommentare sind wichtig.

 Java SE ist ein unglaublicher Ressourcenfresser, wenn CPU zu schwach
 und zu wenig RAM.



 Cu.


 // +++++ Bildfläche erzeugen und füllen mit Bilddaten aus Datei ++++++++++++++
 // BufferedImage Bilddatei laden und puffern per ImageIO aus Url
 //              ohne Mediatracker
 //              ohne internen Cache
 //         Warnung: Sollen die Hilfroutinen zeitkritisch in paint()
 //                       verwendet werden, dann den Quellcode der
 //                       Routinen direkt einbauen in den zeitkritischen
 //                       Programmteil, weil dann enorm an Laufzeit gespart
 //                       wird. Bei Rekursionen möglichst globale Variablen 
 //                       und Rekursion sperren wenn gerade aktiv ist.
 //        Puffer kann benutzt werden um Bildfolge als Ersatz für
 //                        animiertes GIF zu benutzen, da Java animierte
 //                        GIF nicht rendern kann, dafür aber die GIF-
 //                        Einzelbild-Folge.
 //            Datenpuffer existiert unabhängig vom Bildobjekt (Image).
 //                       liegt im Hauptspeicher und ist also kein
 //                            Stream (Streams sind nicht als Zeiger
 //                            speicherbar)
 //        ImageIO liefert BufferedImage, das Teilbilder erzeugen kann
 //                        benutzt keinen internen Cache
 //        Will man den internen Cache von Java nutzen, so muss man
 //                 Toolkit.getDefaultToolkit().getImage(urlUrl);
 //             benutzten, das aber Image liefert.
 //                    Image kennt keine Teilbilder.
 //           BufferedImage ist nicht nach Image castbar.
 //        Mediatracker verlangt ein Image und kann somit mit BufferedImage
 //             nicht umgehen, da nicht castbar auf Image.
 //        Java ist darin komplett inkompatibel.
 // BufferedImage erzeugen mit Bilddimension laut Bilddatei

 // ----- Fläche als gefülltes Image liefern
 //         Warnung: Sollen die Hilfroutinen zeitkritisch in paint()
 //                       verwendet werden, dann den Quellcode der
 //                       Routinen direkt einbauen in den zeitkritischen
 //                       Programmteil, weil dann enorm an Laufzeit gespart
 //                       wird. Bei Rekursionen möglichst globale Variablen 
 //                       und Rekursion sperren wenn gerade aktiv ist.
 // sämtliche Dateien liegen im aktuellen Pfad
 public static BufferedImage GUI2DDiversF06db(String X00)
 // ruft auf AudioDivers.AudioDiversF13d()
 // baut erst den aktuelle Pfad ein 
 //                   (denn dadurch kann Dateiname url-tauglich werden)
 //        und konvertiert dann
 // X00  Dateiname ohne Pfad, wenn null oder Leerkette so kein laden
 // liefert null wenn nicht gepuffert
 {
  // X01 und X02 frei
  BufferedImage X03=null;
  BufferedInputStream X04=null;

  stGUI2DDiversV12cd=" GUI2DDiversF06db() ";

  // +++++ Dateiname prüfen
  if(X00!=null)
  {
   if(!X00.equals(""))
   {
    // +++++ gepufferten Inputstream der Datei im aktuellen Pfad liefern
    X04=AudioDivers.AudioDiversF15d(X00,"",AudioDivers.intAudioDiversV01g,0);
      // X00 Dateiname ohne Pfad
      // X01 Pfad
      //      wenn null oder "" so den Pfad laut Dateilage ermitteln
      //      ansonsten als Pfadangabe verwenden
      //      wenn aber X00 bereits schema-tauglich ist, so X01 nicht verwenden
      //      darf nicht FILe-Schema enthalten
      // X02 NUR laut Konstanten
      //      DateiPfad_Kategorie AppletIntern intAudioDiversV01e
      //      DateiPfad Kategorie Audio intAudioDiversV01f
      //      DateiPfad Kategorie Bilder intAudioDiversV01g
      // X03 -2 so Nicht-File-Schema löschen
      //     -1 so File-Schema löschen
      //      0 so nichts löschen
      //      1 so jedes Schema löschen
      // liefert unpufferten Input des Datenstromes per URL- bzw. Filesystem
      //         null wenn nicht erzeugbar
      //     Der Stream ist offen und somit nicht im Zeigerfeld speicherbar !
    if(X04!=null)
    {
     // +++++ ImageIO.read() benutzten
     //            interner Cache nicht nutzbar
     //            Mediatracker nicht nutzbar
     try 
     {X03=ImageIO.read(X04);
        // ImageIO.read() erzeugt immer BufferedImage-Zeiger
        //              (also impliziertes new(), wobei damit alle
        //                    Parameter des new BufferedImage() nicht
        //                    einstellbar sind: Es wird automatisch bestimmt,
        //                    wie die Bilddaten verarbeitet werden.
        // Transparenz muss Teil des Bildes sein.
    	// Da das Bild geladen wird, ist Transparenz Teil des Bildes.
    	// File als Quelle bei Applet nicht möglich, da das im Browser
    	//     im HTML-Fenster läuft, das nur URL kennt und kein
    	/      lokales Dateisystem, also kein File.
    	// ImageIO.read() benutzt ImageReader
     } 
     catch(IOException e1) 
     {X03=null;
      stGUI2DDiversV12cd+=" 4";
     }
     catch(IllegalArgumentException e2)
     {X03=null;
      stGUI2DDiversV12cd+=" 3";
     }

     // ----- BufferedInputStream schliessen
 		  try
 		  {X04.close();}
 		  catch (IOException e3)
 		  {
 		   // nichts
		   }
    }
    else{stGUI2DDiversV12cd+=" 2";}

   // Mediatracker geht nicht mit BufferedImage !!!!

   // if(boFlag)
   // {
   //  if(boMediaTrackerAktivieren)
   //  {
   //   if(mediaTrackerPuffern!=null)
   //   {
   //    // ++++ Tracker wird benutzt
   //    this.boBild_TrackerBenutzt=true;

   //    // ++++ nächste Gruppe (aus 1 Bild)
   //    intPuffern_MediaTrackerID_Aktuell++;

   //    // ++++ Bild an Tracker übergben
   //    mediaTrackerPuffern.addImage(X04Puffer,
   //                                 intPuffern_MediaTrackerID_Aktuell
   //                                );
   //    // ++++ Tracken starten
   //    try
   //    {mediaTrackerPuffern.waitForID(intPuffern_MediaTrackerID_Aktuell);}
   //    catch (InterruptedException e)
   //    {
   //     boFlag=false;
   //    }

   //    // +++++ Status ermitteln
   //    if(boFlag)
   //    {

   // 	  boFlag=(   (   mediaTrackerPuffern.statusAll(false) 
   // 	               & MediaTracker.ERRORED
   // 	             ) 
   // 	           != 0
   // 	         );        // false so Fehler nicht vorhanden
   //     boFlag=!boFlag;  // true  so Fehler nicht vorhanden

   //     boFlag=(   (   mediaTrackerPuffern.statusAll(false) 
   //                  & MediaTracker.COMPLETE
   //               ) 
   //            != 0
   //           );      // true so complete erkannt 
   //    }

   //    // +++++ Trackstatus merken
   //    this.boBild_TrackerStatus=boFlag;
   //   }
   //  }
   // }
   } // Dateiame nicht leer
   else{stGUI2DDiversV12cd+=" 1";}
  } // Dateiname != null
  else{stGUI2DDiversV12cd+=" 0";}

  if(stGUI2DDiversV12cd.equals(""))
  {if(X03==null)
   {stGUI2DDiversV12cd+=" 5";}
  }

  return X03;
 }


----------



## MaZeFrJoTh (7. Jul 2011)

Ok danke für die umfangreiche Antwort, hab jetzt beim überfliegen noch nicht alles kapiert aber das sieht ja aus, als hätte einer wirklich viel Ahnung von BufferedImages. Danke nochmal.


----------

