2D-Grafik int[] zu BufferedImage konvertieren

0x7F800000

Top Contributor
Hallo leute! Der verlorene Sohn lässt sich wieder blicken... :oops:

Ich versuche schon seit gefühlten zehn Stunden einen einfachen int[]-array mit argb-Werten (roh) in ein int[]-array mit argb-Werten (aber in BufferedImage gewrapped) umzuwandeln, scheitere bisher jedoch kläglich an dieser ganzen image-Ölraffinerie...

argb-Werte sind jeweils in genau ein Integer verpackt, und müssen lediglich als BufferedImage uminterpretiert werden, damit Graphics.drawImage() das ganze fressen kann.

Kleines kompillierbares Beispiel dazu sieht so aus:
Java:
import java.awt.*;
import java.awt.image.*;

public class BufferedImageGeneration {
  public static BufferedImage argbToImage(int[] argb, int w, int h){
	  ColorModel colorModel = ColorModel.getRGBdefault();
	  SampleModel sampleModel = new SinglePixelPackedSampleModel(
			  DataBuffer.TYPE_INT, 
		      w, 
			  h, 
			  new int[]{0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF}
	  );
	  DataBuffer buffer = new DataBufferInt(argb, w * h);
	  WritableRaster raster = Raster.createWritableRaster(sampleModel, buffer, new Point(0,0));
          //funzt auch nich:
          //WritableRaster raster = Raster.createPackedRaster(buffer, w, h, 32, new Point(0,0));
	  BufferedImage img = new BufferedImage(colorModel, raster, false, null);
	  return(img);
  }
  
  public static void main(String... _){
	  int[] argb = new int[4];
	  BufferedImage img = argbToImage(argb, 2, 2);
  }
}

Ich habe mich bemüht, den Vorschlag aus diesem Thread: http://www.java-forum.org/616865-post3.html nachzubauen :rtfm:, aber könnte anscheinend die Lücken "dcm" und "sample" nicht korrekt füllen

KKB schmeißt nämlich folgenden Quatsch:
Code:
Exception in thread "main" java.lang.IllegalArgumentException: 
Raster IntegerInterleavedRaster: width = 2 height = 2 
#Bands = 4 xOff = 0 yOff = 0 dataOffset[0] 0 
is incompatible with ColorModel DirectColorModel: 
rmask=ff0000 gmask=ff00 bmask=ff amask=ff000000
	at java.awt.image.BufferedImage.<init>(Unknown Source)
	at BufferedImageGeneration.argbToImage(BufferedImageGeneration.java:16)
	at BufferedImageGeneration.main(BufferedImageGeneration.java:22)
Woher der verdammte "IntegerInterleavedRaster" auftaucht, ist mir ein Rätsel, bei dem SampleModel steht doch schwarz auf weiß "SinglePixelPacked..." ;(

Ich wäre wirklich äußerst dankbar, wenn mir jemand sagen könnte, was ich das reparieren soll :autsch:
 
Zuletzt bearbeitet:

Marco13

Top Contributor
Nur mal zur Klärung: "Gewrappt" heißt nicht, dass dass der DatenArray des Bildes derselbe sein soll, wie der übergebene Array, sondern nur der gleiche?

Wenn es wirklich in beiden Fällen um ARGB geht, weiß ich nicht, was gegen sowas spricht wie
Java:
	  public static BufferedImage argbToImage(int[] argb, int w, int h){
		  BufferedImage img = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
		  DataBuffer dataBuffer = img.getRaster().getDataBuffer();
		  DataBufferInt dataBufferInt = (DataBufferInt)dataBuffer;
		  int data[] = dataBufferInt.getData();
		  System.arraycopy(argb, 0, data, 0, w * h);
	      return img;
	  }

Falls es doch derselbe Array sein soll, kann man da auch was basteln (ist nicht sooo aufwändig - beim http://www.java-forum.org/codeschnipsel-u-projekte/105991-directbufferedimage.html war es viel komplizierter, weil man da nicht mehr den guten, alten int[] hatte... bei einem int[] kann man den relativ direkt setzen, soweit ich mich erinnere...)
 

0x7F800000

Top Contributor
Marco13, Du bist mein Held! Hab ich Dir das schonmal gesagt? :)

Nur mal zur Klärung: "Gewrappt" heißt nicht, dass dass der DatenArray des Bildes derselbe sein soll, wie der übergebene Array, sondern nur der gleiche?
Meine ganze Formulierung ist wohl sowieso ziemlich unzutreffend: wenn das Bild letztendlich im Grafikkarten-Speicher landet, dann kann es sich unmöglich um dasselbe Array handeln, denn es liegt in einem anderen Speicherchip und ist vom ursprünglichen Array rein physikalisch einige Zentimeter weit entfernt, so in etwa stelle ich mir das jedenfalls vor... :bahnhof:

Wo das Bild genau liegt ist für mich im Moment nicht entscheidend, mir geht es eigentlich nur darum, dass eine mit argb-Ints vollgestopfte Matrix möglichst ohne Umwege auf dem Bildschirm landet, wenn es geht mit möglichst wenig kopiererei, von irgendwelchen Pixel-für-Pixel-Kopier-Manövern ganz zu schweigen.

Inspiriert von Deinem Lösungsvorschlag habe ich einfach das Interface meiner Matrix-Klasse ein wenig umgeändert, sodass diese ihren Inhalt in ein vorgegebenes Array reinkopieren kann, also so:
Java:
class Matrix{
  public void toArray(int[] arr)
}
statt dem da:
Java:
class Matrix{
  public int[] toArray()
}
So kann ich das Data des BufferedImages an die Matrix übergeben, und überflüssige Kopieroperationen komplett vermeiden (das Kopieren der einzelnen Zeilen der Matrix in das Array ist eh unvermeidbar, da muss man mit System.arraycopy ran, das zählt nicht). Läuft, und zwar ziemlich schnell (vernachlässigbar, verglichen mit all den anderen Operationen) Super! :applaus:

Danke schön! :toll:

PS: wie man aber ein BufferedImage aus einem Array instanziiert, bleibt mir jedoch rätselhaft ???:L
 

Marco13

Top Contributor
Es kann schon dasSELBE Array sein. Die Mechanismen, die Hinter dem BufferedImage stehen und das ganze auf den Bildschirm bringen sind dann ja sowieso nochmal versteckt. Wie schon in anderen Threads erwähnt macht Sun da viel... "like a boss" - die haben einfach mehr Kontrolle und sind näher am nativen, das ganze mit den "Managed Images" und direkter Grafikkartenspeichernutzung...

Man muss manchmal ein bißchen aufpassen: Das getDataBuffer liefert den DataBuffer mit dem echten Bild-Array drin - im Gegensatz zu getDataElements, wo die Daten kopiert werden. Sich den DataBuffer zu holen führt dazu, dass das Bild "unmanaged" wird - das heißt, es kann nicht mehr im VRAM gehalten werden, und das Zeichnen wird langsamer. Der Grund, warum dass zwangsläufig zu sein MUSS, ist, dass der Array, den man sich vom DataBuffer abholen kann, eben gerade derSELBE array ist, der Herz und Seele des BufferedImages ausmacht. Das KANN Vorteilhaft sein - denn ganz pragmatisch formuliert könnte das angewendet auf deine Matrix-Klasse bedeuten:
Java:
Matrix matrix = new Matrix(intArrayFromDataBufferOfBufferedImage);

// Wobei
class Matrix{

  private int array[];
  public Matrix(int array[]) { this.array = array; }

  // Das hier schreibt direkt in denSELBEN Array, 
  // der auch im BufferedImage liegt - d.h. die
  // Farbe eines Pixels ändert sich hierdurch beim
  // nächsten Neuzeichnen!
  public void set(int x, int y, int argb) { array[index] = argb; }

  public void toArray(int[] arr)
  {
      // Nichts zu tun, das sind schon dieSELBEN daten...
  }
}

Wenn man das will :reflect: Ggf. kann man Matrix ja als interface definieren, und dann zwei statische Factory-Methoden
Code:
public static Matrix createDefaultMatrix(int w, int h) { ... }
public static Matrix createDirectMatrix(BufferedImage image) { ... }
Wobei das erste eine Instanz erstellt, die die Daten in den Array kopiert, und das zweite eine, bei der "toArray" leer ist, weil sie direkt den Bild-Array enthält. Man muss wohl im ausprobieren, was in welchen Anwendungsfällen das bessere/schnellere/elegantere... oder "weniger hackige" ist :D


EDIT: Das Instanziieren aus einem Array hatte ich nur mal mit einem 3-Byte-RGB-Bild gefrickelt, ist arg kompliziert, aber müßte notfalls auch für int-Arrays hinzukriegen sein. Ich sehe keinen direkten Vorteil, wenn man sich, wie angedeutet, umgekehrt, auch den fertigen Array direkt abholen kann. Aber wenn die "Richtung" durch die Anwendung vorgegeben ist (weil man eben schon einen fertigen Array aus einer anderen Quelle HAT) dann kann man nochmal schauen, ob man das nicht auch hinkriegt...
 
Zuletzt bearbeitet:

0x7F800000

Top Contributor
Das getDataBuffer liefert den DataBuffer mit dem echten Bild-Array drin - im Gegensatz zu getDataElements, wo die Daten kopiert werden.
Ja, das ist klar, sonst hätte es mit dem setzen der Werte so nicht funktioniert, wenn man nur an einer Kopie rumgefummelt hätte...
Sich den DataBuffer zu holen führt dazu, dass das Bild "unmanaged" wird - das heißt, es kann nicht mehr im VRAM gehalten werden, und das Zeichnen wird langsamer. Der Grund, warum dass zwangsläufig zu sein MUSS, ist, dass der Array, den man sich vom DataBuffer abholen kann, eben gerade derSELBE array ist, der Herz und Seele des BufferedImages ausmacht.
Ok, das System glaubt also, dass ich die Kontrolle über das Array behalten will, und lässt es deshalb im normalen Speicher, weswegen es etwas langsamer gezeichnet wird. Das ist eigentlich nicht ganz das was ich will: ich will einfach nur das Bild mit den Werten der Matrix füllen und die Kontrolle über das Array sofort wieder abgeben, sodass das Bild dorthin geladen werden kann, wo es für's Zeichnen am besten aufgehoben ist, etwa Grafikkarten-Speicher. Also ist die Lösung noch nicht ganz das, was in diesem Fall optimal wäre.

Das KANN Vorteilhaft sein - [...]
Java:
[...]
  // Das hier schreibt direkt in denSELBEN Array, 
  // der auch im BufferedImage liegt - d.h. die
  // Farbe eines Pixels ändert sich hierdurch beim
  // nächsten Neuzeichnen!
[...]
Da es für Images irgendwelche native Filter gibt, wäre es eine Überlegung wert!

Wenn man das will :reflect: Ggf. kann man Matrix ja als interface definieren, und dann zwei statische Factory-Methoden [...]
Wie niedlich :D
Eigentlich bastle ich an einem Scala-paket, welches Matrizen in vier verschiedenen "Dichten" und dutzend verschiedenen Layouts mit allen möglichen Körpern, Ringen, Modulen, Gruppen sowie ganz speziellen Typen wie Double und ComplexDouble handhaben soll, mir ist auch schon aufgefallen, dass da ein paar Interfaces angebracht wären ;) Aber momentan bastle ich weniger an der linearen Algebra, sondern an einem Tomographie-Algorithmus, und da braucht man eigentlich nur dichte Double Matrizen. Da es ganze Ströme von Matrizen sind, die man sich gerne als "Filme" anschauen will, musste ich diesen Ausflug in atw.image unternehmen, damit ich sehen kann, was ich da tue :)

EDIT: Das Instanziieren aus einem Array hatte ich nur mal mit einem 3-Byte-RGB-Bild gefrickelt, ist arg kompliziert, aber müßte notfalls auch für int-Arrays hinzukriegen sein. Ich sehe keinen direkten Vorteil, wenn man sich, wie angedeutet, umgekehrt, auch den fertigen Array direkt abholen kann. Aber wenn die "Richtung" durch die Anwendung vorgegeben ist (weil man eben schon einen fertigen Array aus einer anderen Quelle HAT) dann kann man nochmal schauen, ob man das nicht auch hinkriegt...
Es wäre imho vorteilhaft, wenn man dem AWT irgendwie mitteilen könnte "ich hab das array gefüllt, ich brauch's nicht mehr, schieb's in den GraKA-Speicher".

Andererseits muss ich die "Filme" ohnehin künstlich durch Thread.sleep() auf eine angenehme Framerate verlangsamen, also wird das Zeichnen der BufferedImages aus dem normalen Speicher schon nicht so langsam sein :)
 

Marco13

Top Contributor
Ja, das ist klar, sonst hätte es mit dem setzen der Werte so nicht funktioniert, wenn man nur an einer Kopie rumgefummelt hätte...
...
Das ist eigentlich nicht ganz das was ich will: ich will einfach nur das Bild mit den Werten der Matrix füllen und die Kontrolle über das Array sofort wieder abgeben, sodass das Bild dorthin geladen werden kann, wo es für's Zeichnen am besten aufgehoben ist, etwa Grafikkarten-Speicher.

Wie gesagt, die Mechanismen dahinter sind ein bißchen schwer durchschaubar. Dass getDataBuffer ein "unmanagen" verursacht hatte ich auch nur irgendwo gelesen, kann mir aber kaum vorstellen, wie genau das technisch umgesetzt sein sollte. Ich hatte aber irgendwann mal in Quellcode dazu gewühlt, und gesehen, dass eben schon kurz "unter der Haube" nicht-öffentliche Klassen verwendet werden (angefangen bei SunWritableRaster, aber schnell noch viel spezifischer für's OS), die auch gleich ein paar native-Funktionen haben, deswegen ist es schwer, da irgendeine definitive Aussage zu machen.

Vermutlich wäre es am besten, sich da auch mal ein paar dedizierte Benchmarks zu basteln, mit einen 4000x4000-Array und dann mal schauen, wie das Zeichnen und Füllen am schnellsten geht (bzw. bei welchem Ansatz der "tradeoff" am günstigsten ist). In jedem Fall wird es schwierig, dem BufferedImage eine selbst erstellten Array zu geben, und ihm dann zu "versprechen": "Ich mache daran nichts mehr, du kannst jetzt so tun, als hättest du den selbst erzeugt, und die Daten in den VRAM legen"....

Ein Ansatz, der im Moment komisch klingt, bei dem es aber nicht unrealistisch ist, dass er evtl. sehr schnell sein könnte:
Java:
      public static BufferedImage argbToImage(int[] argb, int w, int h){
          BufferedImage img = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
          DataBuffer dataBuffer = img.getRaster().getDataBuffer();
          DataBufferInt dataBufferInt = (DataBufferInt)dataBuffer;
          int data[] = dataBufferInt.getData();
          System.arraycopy(argb, 0, data, 0, w * h);

          BufferedImage result = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
          Graphics2D g = result.createGraphics(); 
          g.drawImage(img,0,0,null);
          g.dispose();

          return img;
      }
Oder in ähnlicher Form sicherstellen, dass das Image, das (zum Zeichnen) zurückgegeben wird eines ist, bei dem man das managed-sein nicht kaputt gemacht hat. Sicher werden die Daten da zweimal kopiert, aber im ersten Fall mit eine arraycopy (schneller geht's nicht), aber im zweiten Fall wird ein BufferedImage in ein BufferedImage gleichen Typs gemalt - das dürfte auch dann noch sehr schnell gehen, wenn das erste NICHT im VRAM liegt (Sun macht in der Drawing-Pipeline, die vom Graphics angesprochen wird, da einige fies-spezifische instanceof-Abfragen und so... Man kann also davon ausgehen, dass dort zumindest keine unnötigen Umwege über ColorModel und SampleModel gegangen werden...)

Als Mittelding bzw. Alternative dazu könnte man das Bild, das man in das neu erstellte (und garantiert gemanagte) reinmalt, auch mit
Java:
    public static BufferedImage argbToImage(int[] argb, int w, int h){
    	
    	ColorModel colorModel = ColorModel.getRGBdefault();
        int bandmasks[] = new int[]{0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000};
    	DataBuffer d = new DataBufferInt(argb, w*h);
    	WritableRaster writableRaster = Raster.createPackedRaster(d, w, h, w, bandmasks, new Point(0,0));
	    BufferedImage bufferedImage = new BufferedImage(colorModel, writableRaster, false, new Hashtable<Object, Object>());
	    return bufferedImage;
    }
erstellen: Damit wird in diesem Bild derSELBE Array verwendet, wie der übergebene (den man sich z.B. von der Matrix geholt haben könnte). Das Bild dann in ein neu erstelltes, gemanagtes Bild reinmalen dürfte aus dem oben genannten Gründen entsprechend genauso schnell sein, und man spart sich das arraycopy.

Theoretisch könnte man auf dem Raster, das dort erstellt wird, noch sowas wie
Java:
	private static void unsteal(WritableRaster writableRaster)
	{
		try
		{
	    	Class<?> c = writableRaster.getClass();
	    	Method method = c.getMethod("setStolen", Boolean.TYPE);
	    	method.invoke(writableRaster, false);
		}
		catch (SecurityException e)
		{
			e.printStackTrace();
		}
		catch (NoSuchMethodException e)
		{
			e.printStackTrace();
		}
		catch (IllegalArgumentException e)
		{
			e.printStackTrace();
		}
		catch (IllegalAccessException e)
		{
			e.printStackTrace();
		}
		catch (InvocationTargetException e)
		{
			e.printStackTrace();
		}
	}
aufrufen, was theoretisch bewirken könnte oder sollte, dass das entstehende Bild "managed" ist. (Zumindest werden Änderungem am Array dann auch nicht mehr im Bild sichtbar). SunWritableRaster#setStolen(false) ist nämlich der einzige wesentliche Unterschied zwischen dem oben verwendeten Bilderstellungsprozess, und dem, der wirklich intern mit einem "new BufferedImage" verwendet wird. Aber erstens ist das mit Reflection eben so eine Sache, und zweitens müßte man noch schauen, ob man die Vermutung, dass das Bild danach managed ist, durch Benchmarks ... bekräftigen könnte.
 

0x7F800000

Top Contributor
Als Mittelding bzw. Alternative dazu könnte man das Bild, das man in das neu erstellte (und garantiert gemanagte) reinmalt, auch mit
Java:
    public static BufferedImage argbToImage(int[] argb, int w, int h){
    	
    	ColorModel colorModel = ColorModel.getRGBdefault();
        int bandmasks[] = new int[]{0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000};
    	DataBuffer d = new DataBufferInt(argb, w*h);
    	WritableRaster writableRaster = Raster.createPackedRaster(d, w, h, w, bandmasks, new Point(0,0));
	    BufferedImage bufferedImage = new BufferedImage(colorModel, writableRaster, false, new Hashtable<Object, Object>());
	    return bufferedImage;
    }
erstellen
Ach... Ich habe in meinem ursprünglichen code also lediglich die Reihenfolge der masken in diesem behämmerten bandmasks-array vertauscht? :wuerg:

So funzt's scheinbar doch:
Java:
public static BufferedImage argbToImage(int[] argb, int w, int h){
	  ColorModel colorModel = ColorModel.getRGBdefault();
	  SampleModel sampleModel = new SinglePixelPackedSampleModel(
			  DataBuffer.TYPE_INT, 
		      w, 
			  h, 
			  new int[]{0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000}
	  );
	  DataBuffer buffer = new DataBufferInt(argb, w * h);
	  //WritableRaster raster = Raster.createPackedRaster(buffer, w, h, 32, new Point(0,0));
	  WritableRaster raster = Raster.createWritableRaster(sampleModel, buffer, new Point(0,0));
	  //WritableRaster raster = Raster.createPackedRaster(buffer, w, h, w, new int[]{0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000}, new Point(0,0));
	  BufferedImage img = new BufferedImage(colorModel, raster, false, null);
	  return(img);
  }
oh man! Danke für die Korrektur :D

Kr0e hat gesagt.:
Kannst du evt. OpenGL nutzen ? Damit wäre das alles garkein Problem mehr.
Hm, in der nächsten Version bräuchte ich auch 3D-Plots, und würde somit um JOGL nicht drumrumkommen, vielleicht ist es dann leichter, grundsätzlich alles mit JOGL zu rendern. Ich werde den Tipp später genauer unter die Lupe nehmen, aber für diesen Moment belasse ich es erstmal beim BufferedImage & AWT: bin ziemlich unter Zeitdruck.
 
Zuletzt bearbeitet:
S

Spacerat

Gast
Ich hab' grad' wieder etwas mehr Zeit und mich deswegen mal mit den Images auseinander gesetzt. Im Zeitalter von [c]java.nio[/c] und der Möglichkeit bzw. für JOGL und LWJGL sogar der Notwendigkeit von DirectBuffern erschien mir die Verwendung simpler Arrays alles andere als zeitgemäß. Daher hier mal Ansatzweise ein Versuch für BufferedImages DirectBuffer zu verwenden. Ziel ist es, ein BufferedImage zu erstellen, von welchem man per[c]getRaster().getDataBuffer().getData()[/c] Buffer zu bekommen, welche in JOGL und LWJGL direkt an den Texturspeicher übergeben werden können. BufferedImage soll dabei so abwärtskompatibel wie möglich bleiben. Insgeheim hoffe ich auch, dass Imageprocessing auf die Art ebenfalls schneller gehen wird - naja, abwarten und Tee trinken, während man weiter coded und ausgiebig testet.
[EDIT]Eines noch... Möglichkeiten diesen Ansatz zu posten gab es natürlich einige viele. Hab' mich für diesen Thread entschieden, da hier neben Imageprocessing auch gleichzeitig noch JOGL erwähnt wurde.[/EDIT]
 

Anhänge

  • DirectImage.jar
    55,4 KB · Aufrufe: 6
Zuletzt bearbeitet von einem Moderator:

Marco13

Top Contributor
BTW: (Dort ist das Thema dann etwas abgedriftet) Vielleicht kann man die Ansätze kombinieren und das ganze damit etwas "profunder" aufziehen (auch mit Benchmarks und so...) ... :reflect: Werd' mit den Code bei Gelegenheit mal ansehen...
 
S

Spacerat

Gast
Ansätze kombinieren? Warum nicht...
Ich bin allerdings auf dem Pfad, es auch ausserhalb irgendwelcher Hardware-Kontexte zu nutzen. Bin bisher auch nur soweit, dass ich RGB(A) und HSB(A) Bilder erstellen (beides im Prinzip TYPE_INT_ARGB), mir deren Graphics-Kontext holen und dann in diesen Zeichnen kann und das alles ohne die SUN-States "stolen" oder "accellerated". Den Status "accellerated" verspreche ich mir ja eigentlich schon allein durch die Verwendung der DirectBuffer. Mir ist im Ansatz im übrigen auch schon klar, dass in OpenGL-Kontexten ausschliesslich "PIXEL_SIZED" Images verwendet werden können, weil dem TexturBuffer jegliche Referenzen zu den Paletten von "INDEXED" Images fehlen würden. Kurz gesagt, ich bin gerade mal soweit, dass ich herausgefunden habe, wie Graphics bzw. Graphics2D in den Buffer eines Images zeichnet.
 

Marco13

Top Contributor
Was meinst du mit Hardware-Kontext? Wenn man das "DirectBufferedImage" erstellt, kann man da reinzeichnen - und die Daten landen im DirectBuffer. Allerdings muss man sich noch genauer ansehen, wann welche Methode verwendet wird: Wenn man z.B. ein BufferedImage in ein anderes zeichnet, werden intern abhängig vom Typ der Bilder u.U. spezialisierte Methoden verwendet.
 
S

Spacerat

Gast
Was meinst du mit Hardware-Kontext?
Alle Methoden, Funktionen und Objekte eines jeden APIs die Imagedaten in den Speicher einer Grafikkarte übertragen.
Wenn man das "DirectBufferedImage" erstellt, kann man da reinzeichnen - und die Daten landen im DirectBuffer. Allerdings muss man sich noch genauer ansehen, wann welche Methode verwendet wird: Wenn man z.B. ein BufferedImage in ein anderes zeichnet, werden intern abhängig vom Typ der Bilder u.U. spezialisierte Methoden verwendet.
Das ist mir bewusst, im Prinzip ahne ich auch schon wann welche Methoden aufgerufen werden könnten. Deswegen warte ich an diversen Stellen halt mit einer [c]UnsupportedOperationException[/c] auf.
 

Marco13

Top Contributor
Hmja, die Hardware-Sache war im Prinzip klar. Man muss sich halt überlegen, welche BufferedImage.TYPEs man anbieten will (und kann). Also, ob man z.B. einen CUSTOM-Type erstellt, der dann nicht ARGB sondern RGBA verwendet oder so. Aber genau das meinte ich mit "profunder" aufziehen: Sich genau über das mehr Gedanken zu machen.
Und über die Frage, welche Methoden wo aufgerufen werden. In dem verlinkten Thread hatte ich auch noch eine Version (AFAIR) ohne UnsupportedOperations gepostet, aber da muss man davon ausgehen, dass bestimmte Operationen schrecklich langsam sind: Ein BufferedImage.TYPE_INT_ARGB in ein DirectBufferedImage gleichen typs zu malen könnte theoretisch (!) zu einem buffer.put(array) zusammenschnurren, aber da ist vieles nicht so leicht wie es im ersten Momen aussieht. Wenn da noch SampleModel und ColorModel reinkommen, kann das ganze ziemlich tricky werden....
 
S

Spacerat

Gast
SampleModel und ColorModel... Tja, das sind genau die Punkte, die ich nicht wirklich verstehe. Klar dabei ist, dass es für verschiedene Farbmodelle jeweils genau zwei Möglichkeiten gibt Bilddaten (Pixel) zu speichern, erstens band- und zweitens pixelweise. Für erstere Methode gibt es erneut zwei Möglichkeiten, erstens alle Bänder in einem Puffer mit bestimmten Offsets und zweitens alle Bänder einzeln in separaten Puffern mit Offset 0. Darüber hinaus können die entstehenden Puffer noch auf zwei Arten organisiert sein, erstens zeilen- und zweitens spaltenweise. Dieses hin und her wandeln ist im Prinzip das, was du als "tricky" bezeichnest aber man könnte sich hier bereits auf ein Model einigen, Pixelweise / Zeilenweise bietet sich an. Auf jeden Fall hoffe ich, dass mir wenigstens dieser ganze Pixel- und Scanline-Stride-Humbug erspart bleibt.
 
Zuletzt bearbeitet von einem Moderator:

Marco13

Top Contributor
Ja, das Sample/Color-Model zeug kann schon konfus sein, über die Details habe ich mir bisher auch noch nicht viele Gedanken gemacht - es ist einfach sehr selten wirklich relevant: "Mach mir ein BufferedImage" und gut is' ... Bei einer eigenen Implementierung würde man in erster Näherung wohl so vorgehen, wie ich in dem Beispiel: Schauen, wie ein BufferedImage.TYPE_INT_ARGB das macht, aber eben alles, was mit dem Array zu tun hat, auf einen IntBuffer umbiegen. Trotzdem gibt's noch viele(!) "Details" zu klären.
Der Scanline-Stride "Humbug" wird wohl auch wichtig - weil da ja genau defniert wird, wie irgendwelche Daten in den array/directBuffer geschrieben wird. Spätestens, wenn man sich mit getSubImage ein Bild holt, kann man da ja nicht die Daten "irgendwie" reinschreiben...
Werd' mal zusehen, wann ich da meinen Stand wieder auffrischen kann... ist 'ne Weile her dass ich das gemacht hatte.
 
S

Spacerat

Gast
Der Scanline-Stride "Humbug" wird wohl auch wichtig - weil da ja genau defniert wird, wie irgendwelche Daten in den array/directBuffer geschrieben wird. Spätestens, wenn man sich mit getSubImage ein Bild holt, kann man da ja nicht die Daten "irgendwie" reinschreiben...
Werd' mal zusehen, wann ich da meinen Stand wieder auffrischen kann... ist 'ne Weile her dass ich das gemacht hatte.
Diese Strides sind allem Anschein nach nur für die Hintergrundoperationen der Sun-Klassen beim vergrössern und verkleinern interessant und weniger für Subtiles bzw. Images. Dadurch kann ein Bildpunkt mehrere Pixel also Pufferelemente belegen und eine gescalete Instanz des Puffers in den Grafikspeicher gelegt werden. Für Imageprocessing aber eigentlich nur ein Punkt wenn nicht sogar der entscheidende der unheimlich aufhält, eben weil man dort Daten halt nicht "irgendwie" reinschreiben kann. Ein BufferedImage ist in Breite und Höhe festgelegt und ein setRGB(x, y, rgb) könnte zur Folge haben, dass bei einem gescaletem Image gleich mehrere Pixelelemente geschrieben werden müssen. Das ist denke ich auch der Hauptgrund, warum ein Bild als Kopie (stolen) gekennzeichnet wird, wenn man sich blos den Pixelpuffer per [c]raster.getDataBuffer().getData()[/c] holt, denn in diesen kann nunmal jedes Pixelelement, auch wenn es Teil eines vergrösserten Punktes ist, einzeln verändert werden. Für mich ist es deswegen genau jenes Detail, warum ich es als "Humbug" bezeichne und es vermeiden will. Bleibt nur zu hoffen, dass ImageBuffer ohne diesen "Humbug" etwa ebenso performant werden, als befänden sie sich im Grafikspeicher.
 

Marco13

Top Contributor
An welcher Stelle da skalierung nun eine Rolle spielt, konnte ich spontan nicht nachvollziehen. Der scanline stride ist meinem Verständnis nach dazu da, zu defnieren, wo ein Pixel einer Spalte in Relation zum gleichen Pixel der nächsten Spalte liegt - bei einem Image mit 1000 Pixeln breite wäre der Stide ben 1000 Pixel - aber wenn man von diesem Bild ein SubImage mit 500 Pixeln Breite erstellt, wäre der Stride immernoch 1000 Pixel. Aber vielleicht meinen wir auch gerade was unterschiedliches.
 
S

Spacerat

Gast
An welcher Stelle da skalierung nun eine Rolle spielt, konnte ich spontan nicht nachvollziehen. Der scanline stride ist meinem Verständnis nach dazu da, zu defnieren, wo ein Pixel einer Spalte in Relation zum gleichen Pixel der nächsten Spalte liegt - bei einem Image mit 1000 Pixeln breite wäre der Stide ben 1000 Pixel - aber wenn man von diesem Bild ein SubImage mit 500 Pixeln Breite erstellt, wäre der Stride immernoch 1000 Pixel. Aber vielleicht meinen wir auch gerade was unterschiedliches.
Denke auch, dass wir aneinander vorbei reden, denn für das was du da meinst genügt definitiv die normale Breiten- bzw. Höhenangabe.
Wie gesagt, ein Bild hat eine gewisse Breite und eine gewisse Höhe. Für eine allgemeine Hardware wäre die allgemeine Einheit für diese "Maße" halt Pixel bzw. Punkte. Ein solcher Pixel ist für eine Hardware normalerweise (afaik sogar immer) in seinen Ausdehnungen festgelegt und lässt sich nicht ändern. Wollte man nun ein ein Pixel innerhalb eines HW-Kontextes vergrössern, bleibt einem nur der Weg, einzelne virtuelle Bildpunkte über mehrere beieinander liegende Pixel zu verteilen. Kurz gesagt, es wird nicht die Anzahl der virtuellen Bildpunkte per "width" und "height" verändert, sondern lediglich die Pixelbreite (Pixelstride) und -höhe (Scanlinestride) dieser virtuellen Bildpunkte neu festgelegt (siehe Illustration). Für die Darstellung einer Grafik in verschiedenen Grössen auf ein und der selben Hardware sind diese Werte unabdingbar, jedoch für Grafiken, welche noch bearbeitet werden sollen, alles andere als, es sei denn, man möchte eine Grafik in eine andere skaliert hineinkopieren. Sun aber war der Meinung, diese Werte zu jeder Tages und Nachtzeit in ihren BufferedImages verwenden zu müssen, ja auch dann noch, wenn der Bildpuffer längst nicht mehr in der Hardware liegt bzw. als "stolen" markiert wurde.
 

Anhänge

  • Strides.png
    Strides.png
    9,2 KB · Aufrufe: 43
Zuletzt bearbeitet von einem Moderator:

Marco13

Top Contributor
Meinen wir vielleicht unterschiedliche Scanline Strides? (Oder einmal eine Scanline und einmal tatsächlich den Scanline Stride?) Ich kenne diesen Begriff aus verschiedenen Zusammenhängen, und immer in der gleichen Bedeutung, nämlich der, wie sie z.B. in der IntegerInterleavedRaster-Klasse steht (auch wenn ich bei der Beschreibung oben Zeilen und Spalten verwechselt hatte... :oops: )
Java:
        /**
         * Returns the scanline stride -- the number of data array elements between
         * a given sample and the sample in the same column of the next row.
         */
        public int getScanlineStride() {
            return scanlineStride;
        }
Das wird eben beim setzen eines einzelnen Pixels verwendet, z.B. bei
Code:
int off = (y - minY) * scanlineStride + (x - minX)...

Ein Bild mit einer Breite von 500 Pixeln kann auch einen Scanline Stride von 1000 Pixeln haben. Der Pixel an der Position (0,0) hat dann (im linearen Buffer) den Offset 0+scanlineStride*0
Position (0,1) : Offset 0+scanlineStride*1
Position (0,2) : Offset 0+scanlineStride*2
...
Wenn man den Offset im linearen Buffer immer als x+y*width ausrechnen würde, würde das ja nur passen, wenn die "breite des buffers" (also der scanline stride) gleich der Breite des Bildes ist...

Bin aber gerade gar nicht sicher, ob wir uns über solche Details die Köppe einschlagen müssen :)

Hab gerade mal in die JAR geschaut, und gesehen, dass du das ganze ja schon deutlich "breiter" aufgezogen hast, als ich meinen Test damals - und ... anders. Ich hatte da z.B. ein "DirectIntegerInterleavedRaster" erstellt, ... und kann mir gerade nicht ganz vorstellen, wie man da drumrumkommen soll... bei getDataElements/setDataElements muss man doch wissen, dass man einen DirectBuffer hat, wenn man nicht alle Pixel einzeln setzen will...? (Von Dingen wie createCompatibleWritableRaster & Co mal ganz abgesehen) ... Aber da werde ich mir den Code wohl noch genauer ansehen müssen.
 
S

Spacerat

Gast
Okay... das IntegerInterleavedRaster hatte ich mir noch nicht angesehen, deine Formeln kommen mir aber sehr bekannt vor -> [c]y * width + x[/c] oder besser, die allgemeine Indexberechnung eines Zeile/Spalte-Wertepaares in einen Puffer bzw. ein Array. Habe also zunächst erst mal kein Plan, was Sun da verzapft hat und möglicherweise komme ich da auch nie drauf. Die Strides von denen ich Rede haben eine ganz andere Bedeutung:
Code:
offset = y * (width * pixelstride) + x * scanlinestride;
for(int p = 0; p < scanlinestride; p++) {
  buffer[offset+p] = colorValue;
}
Schon wissen wir möglicherweise beide, was bei deiner Version erreicht wurde, es wurde anscheinend schlicht eine Multiplikation eingespart. Ich hab den Quellcode des IntegerInterleavedRaster gerade nicht zur Hand, aber ich kann mir sehr gut vorstellen, dass auch dort nach der Berechnung des Offsets eine ähnliche Schleife wie bei mir folgt. Bei deiner Version ist "scanlinestride" die eigendliche Breite des Bildes, bei meiner "width * pixelstride". Bei deiner Version erkennt man deutlich ein neu geschaffenes Problem; Versuch' mal das Bild erneut zu skalieren. Ich könnte dieses recht simpel tun, indem ich Pixel- und Scanlinestride zur Laufzeit als Parameter übergebe, vorzugsweise erst dann, wenn das Bild angezeigt werden soll. Ansonsten sind bei mir beide Werte stets 1, womit wir wieder bei der allgemeinen Indexberechnung wären.
[EDIT]Ach ja... solange die besagten Werte bei mir 1 bleiben, ist logischerweise auch diese Schleife zum setzen eines Bildpunktes hinfällig.[/EDIT]
[EDIT]Nun hab' ich schon so oft wieder an meinem Pseudocode rum editiert, aber irgendwie weis ich nicht mehr genau wie das ging, nur halt das es geht. Werd' wohl mal wieder meine uralte Amiga-Buch-Bibliothek hervor kramen müssen, sofern die überhaupt noch existiert. :oops:[/EDIT]
 
Zuletzt bearbeitet von einem Moderator:

bERt0r

Top Contributor
Ich hab mir jetzt nicht alles durchgelesen, aber hast du das schon versucht?
Java:
image.setRGB(0, 0, width, height, buffer, 0, width);
Läuft ziemlich flott.
 

Anhänge

  • IntToImg.jar
    3,6 KB · Aufrufe: 2
S

Spacerat

Gast
Herber Rückschlag!
Zunächst erst mal die korregierte Formel: [c]offset = y * width * pixelWidth * pixelHeight + x * pixelWidth * pixelHeight[/c]. Mit dieser können einzelne Bildpunkte eines vergrösserten Bildes eingefärbt werden. Ein Bildpunkt besteht dabei wie gesagt aus mehreren Pixeln (pixelWidth * pixelHeight).
Also, was ich vorhatte:
Ich wollte Bilddaten in DirectBuffern ablegen, um erstens Java-Heap zu sparen, zweites diese Buffer für GL-Kontexte ebenso direkt verfügbar machen und drittens per Graphics bzw. Graphics2d in diese Buffer zeichnen können. Da sich die Attribute Höhe, Breite und Farbtiefe eines Bildes bzw. einer Zeichenfläche kaum ändern, ersparte ich mir auch diese Bildpunktberechnungen und legte Pixelhöhe und -breite auf jeweils 1 fest.
So weit, so gut... Beim Zeichnen in ein solches Bild scheint es keinerlei Performanceeinbussen zu geben. Diese gibt es erst, wenn es angezeigt werden soll und das nicht zu knapp. Ich kann mir plötzlich auch vorstellen, warum.
Erkenntnisse:
Der Datenpuffer muß zum Anzeigen logischerweise in die Hardware (Graka) übertragen werden und genau dort hat man in Java anscheinend keinen direkten Zugriff mehr darauf. Wann immer ein Raster erstellt wird, dessen Puffer eine in der Applikation erreichbare Referenz besitzt, gilt dieses Raster als "stolen". Markos Methode mit [c]createPackedRaster()[/c] hilft da auch nicht. Da Sun also jeglichen Direktzugriff auf die Puffer unterbindet, kann man davon ausgehen, dass die Java2D-Klassen allesamt völlig transparent ihrerseits direkt auf den Speicher der Graka zugreifen und die Bildpuffer dort relativ "dynamisch", ähnlich einer [c]ArrayList[/c], also Grösse verdoppeln/halbieren, anlegt und fortan auch mit(!) verwendet. So bekäme auch die exessive Nutzung der Strides für mich einen Sinn, kein normaler Mensch würde sonst Schrittweiten und Schleifen auch für 1x1-Pixelgrössen verwenden oder irgendwie implementieren.
Ein Puffer wird wie gesagt als "stolen" gekennzeichnet, sobald eine Referenz darauf in der Applikation verfügbar ist. Ganz einfach deswegen, weil Java2D nun nicht in der Lage ist, den Java- und den Hardwarepuffer synchron zu halten und deswegen in jedem einzelnen Frame den gesamten Javapuffer erneut in die Hardware kopieren muss. Ständiges Kopieren kann dabei auch ständiges reservieren von Speicher bedeuten. Das an diesen Thesen durchaus was dran ist, zeigt dieses Swingproblem welches HDI mal hatte, oder vllt. auch noch hat, zumindest erinnert mein Versuch im Anhang sehr stark daran.
Zuletzt möchte ich noch klären, wie ich darauf komme, dass die Performanceeinbrüche erst bei der Anzeige zustande kommen. Dazu habe ich die LWJGL Version von NeHe's Lektion 6 so umgebaut, dass die Textur letztendlich in ein DirectBufferedImage landet, dessen Puffer sich sehr einfach per [c]glTexImage2D[/c] in den Speicher der Hardware übergeben lässt. Im Renderloop besorgte ich mir nun das Graphics2D-Objekt dieser Textur um ein paar Linien darauf zu zeichnen. Leider reichte hier ein simples Zeichnen in den Puffer nicht aus, der Puffer musste mit jedem Frame erneut an die Hardware übergeben werden, damit die Änderungen sichtbar wurden. Ich habe zwar leider keine Zahlen, aber diese stete Übergabe reduzierte die Framerate deutlich sichtbar, während beim Zeichnen der Linien keine Performanceeinbrüche sichtbar waren. Naja... immerhin konnte ich schon mal per Suns Graphics2D-Objekt in eine Textur zeichnen.
 

Anhänge

  • DirectImage.jar
    202,6 KB · Aufrufe: 3
Zuletzt bearbeitet von einem Moderator:
S

Spacerat

Gast
Sorry wegen Doppelpost, aber zum Editieren ist's leider bissl' spät.
Sollten bezüglich der Performance irgendwelche Vorschläge bezüglich VolatileImage kommen dann denk' ich mal, das es auch dafür zu spät ist, denn auch damit habe ich genügend fehlgeschlagene Experimente hinter mir. In Sachen Kompatibilität, Platformunabhängigkeit und Implementation des Graphics-Kontexts ist das einfach noch nicht ausgereift.
 

Marco13

Top Contributor
Hmja, einige der Punkte hatte ich ja schon in ähnlicher Form angedeutet. Dass ich dieses DirectBufferedImage damals erstellt hatte, hatte ja einen Hintergrund - nämlich in erster Linie Swogl , aber allgemein eben die Möglichkeit mit Graphics2D in eine GL-Textur reinzuzeichnen. Das hatte ich mal probiert, und es hat gut funktioniert, aber bezüglich der Performance hatte ich nur ein paar erste Tests gemacht (die Ergebnisse sind wenig systematisch und etwas über das Forum verstreut, z.B. in http://www.java-forum.org/awt-swing-swt/114728-java2d-jogl-interoperability-2.html#post740599 oder http://www.java-forum.org/codeschnipsel-u-projekte/120521-swogl-swing-meets-opengl.html#post784416 ). Je nach Art der Umsetzung war immer ein Teil der Pipeline langsamer - manchmal das Zeichnen von Linien oder Bildern in das Direct-Graphics2D, manchmal das Zeichnen des Bildes selbst - aber speziell letzteres wäre ja gar nicht notwendig, wenn man das Bild nur als GL-Textur verwenden will.

Den Buffer der Textur mit glMapBuffer zu holen und in das DirectBufferedImage zu stecken ging (mit einem kleinen Trick im Graphics2D) aber ganz gut... FALLS das nicht schon in der JAR ist: Wie hast du das denn umgesetzt? (FALLS es drin ist, werd' ich es mir hoffentlich bald mal genauer ansehen können - der Thread hier liegt schon in meiner "TODO"-Liste, leider bin ich im Moment etwas unter Wasser, hoffentlich finde ich bald ein bißchen mehr Zeit...)
 
S

Spacerat

Gast
... Wie hast du das denn umgesetzt?
Gar nicht :( Ich suche ja halt 'ne Möglichkeit, wie ich direkt ins Grafik-Ram bzw. in einen synchronisierten Puffer schreiben kann. Hatte zu nächst angenommen, dass LWJGL usw. genau zu diesem Zweck DirectBuffer benötigen. Nun scheint diese Forderung allerdings nur noch Schikane. :(
glMapBuffer? Was macht das... nix sagen, ich schau's mir grad' selbst an.
[EDIT]Ich häng' nochmal die veränderte Form der besagten NeHe-Tuts und JGL (wird zur Darstellung der Framerate benötigt) an. Dazu noch 2 Bilder, in denen man den Unterschied sieht. Das Ganze benötigt zusätzlich noch LWJGL. Das aber muss ich hier hoffentlich nicht hochladen. Das Problem: Bei ohne Puffer neu schreiben (in die Graka übertragen) sieht man auch keine Änderungen in der Textur.[/EDIT]
 

Anhänge

  • lwjgl_ext_src.jar
    29,3 KB · Aufrufe: 3
  • mit Puffer neu schreiben.jpg
    mit Puffer neu schreiben.jpg
    51 KB · Aufrufe: 38
  • ohne Puffer neu schreiben.jpg
    ohne Puffer neu schreiben.jpg
    52,2 KB · Aufrufe: 36
  • Nehe_6_altered.jar
    7,1 KB · Aufrufe: 2
Zuletzt bearbeitet von einem Moderator:
Ähnliche Java Themen
  Titel Forum Antworten Datum
Zar von Domarus JFrame zu BufferedImage konvertieren AWT, Swing, JavaFX & SWT 3
I Arbeitsspeicherverbrauch BufferedImage.TYPE_INT_RGB vs. TYPE_3BYTE_BGR AWT, Swing, JavaFX & SWT 6
H BufferedImage zurücksetzen funktioniert nicht AWT, Swing, JavaFX & SWT 12
L AWT Ändern der Farbe eines BufferedImage mit Farbähnlichkeit AWT, Swing, JavaFX & SWT 5
I GEmaltes BufferedImage löschen AWT, Swing, JavaFX & SWT 3
cool_brivk24 BufferedImage einem ClickEvent hinzufügen AWT, Swing, JavaFX & SWT 13
cool_brivk24 AWT BufferedImage wird nicht geladen AWT, Swing, JavaFX & SWT 17
J linken Bildausschnitt eines BufferedImage abschneiden AWT, Swing, JavaFX & SWT 4
S 2D-Grafik User-BufferedImage rotieren im Zentrum und ohne "anpassung" AWT, Swing, JavaFX & SWT 2
C Pixel-Rendering/Animation Performance in BufferedImage AWT, Swing, JavaFX & SWT 1
H Swing BufferedImage zeichnen AWT, Swing, JavaFX & SWT 1
C Swing BufferedImage zeichnen und JLabels setzen. AWT, Swing, JavaFX & SWT 17
G Subimage von BufferedImage speichern AWT, Swing, JavaFX & SWT 4
D JPanel Graphic2D als BufferedImage Speichern AWT, Swing, JavaFX & SWT 5
D BufferedImage -> Feature Extraktion. Unterschiedliche BufferedImage imageTypes problem AWT, Swing, JavaFX & SWT 4
I 2D-Grafik Shape aus BufferedImage "löschen" AWT, Swing, JavaFX & SWT 2
M 2D-Grafik LookupOp Operation auf BufferedImage AWT, Swing, JavaFX & SWT 7
GianaSisters 2D-Grafik BufferedImage.getSubimage - Frage AWT, Swing, JavaFX & SWT 7
P BufferedImage schlechte Qualität beim Abspeichern AWT, Swing, JavaFX & SWT 9
S BufferedImage als schwarz-weiß-Bild AWT, Swing, JavaFX & SWT 3
Luk10 BufferedImage[...].getData() vs BufferedImage.setRGB() AWT, Swing, JavaFX & SWT 2
D Schnelles kopieren von Pixeln in ein BufferedImage AWT, Swing, JavaFX & SWT 25
J Flackern wie mit BufferedImage beheben AWT, Swing, JavaFX & SWT 4
N Swing BufferedImage neu laden AWT, Swing, JavaFX & SWT 10
N 2D-Grafik BufferedImage, Line2D, Swing und die Probleme AWT, Swing, JavaFX & SWT 5
Luk10 BufferedImage auf ein anderes BufferedImage zeichnen AWT, Swing, JavaFX & SWT 6
P BufferedImage auf JPanel AWT, Swing, JavaFX & SWT 11
K 2D-Grafik BufferedImage eingelesen, welches Modell?! AWT, Swing, JavaFX & SWT 2
T BufferedImage bei paintComponent AWT, Swing, JavaFX & SWT 6
C 2D-Grafik BufferedImage laden, Frage zum Code AWT, Swing, JavaFX & SWT 2
H 2D-Grafik BufferedImage aus Integer-Array AWT, Swing, JavaFX & SWT 3
Luk10 2D-Grafik BufferedImage sauber rotieren AWT, Swing, JavaFX & SWT 16
P Image mehrfach in ein BufferedImage zeichnen AWT, Swing, JavaFX & SWT 7
A BufferedImage nach dem Speichern immer schwarz AWT, Swing, JavaFX & SWT 8
J Bild aus Datei in BufferedImage laden AWT, Swing, JavaFX & SWT 4
E BufferedImage Alphaknal ein- und ausblenden AWT, Swing, JavaFX & SWT 7
N BufferedImage zeichnen AWT, Swing, JavaFX & SWT 4
D BufferedImage Größe skalieren AWT, Swing, JavaFX & SWT 2
P Swing Vom BufferedImage bei paintComponent nur soviel zeichnen, wie nötig AWT, Swing, JavaFX & SWT 3
B 2D-Grafik BufferedImage Performance AWT, Swing, JavaFX & SWT 3
Y frage zu BufferedImage AWT, Swing, JavaFX & SWT 7
E AWT RenderedImage aus BufferedImage erzeugen, um Bild abzuspeichern? AWT, Swing, JavaFX & SWT 4
S Unterscheiden ob ein Graphics-Objekt von einer JComponent oder einem BufferedImage kommt..? AWT, Swing, JavaFX & SWT 4
A 2D-Grafik BufferedImage wird nicht eingezeichnet AWT, Swing, JavaFX & SWT 3
G 2D-Grafik BufferedImage Hintergrund immer schwarz AWT, Swing, JavaFX & SWT 4
Developer_X Swing Auf ein BufferedImage mit Graphics/Graphics2D zeichnen AWT, Swing, JavaFX & SWT 6
J AWT BufferedImage to 2DArray AWT, Swing, JavaFX & SWT 10
R Bild drehen UND skalieren (Image bzw BufferedImage) AWT, Swing, JavaFX & SWT 5
J JPanel in Bufferedimage AWT, Swing, JavaFX & SWT 3
1 BufferedImage in byte[], dann in String und zurück AWT, Swing, JavaFX & SWT 7
J Swing paintComponent() - repaint() - BufferedImage anzeigen AWT, Swing, JavaFX & SWT 5
C BufferedImage-Fehler? Falsches Bild wir gezeichnet AWT, Swing, JavaFX & SWT 5
B BufferedImage Builder AWT, Swing, JavaFX & SWT 15
F Transparentes BufferedImage über BufferedImage AWT, Swing, JavaFX & SWT 12
F Größe von BufferedImage ändern AWT, Swing, JavaFX & SWT 27
I Swing JComponent als BufferedImage speichern AWT, Swing, JavaFX & SWT 18
Dragonfire Swing Zoom-Vorgang optimieren [BufferedImage] AWT, Swing, JavaFX & SWT 2
2 Memory Leak mit BufferedImage !! AWT, Swing, JavaFX & SWT 15
X BufferedImage maximiert in JFrame anzeigen? AWT, Swing, JavaFX & SWT 2
R JPanel - BufferedImage - zeichnen großer Bilder AWT, Swing, JavaFX & SWT 2
R JTable - TableCellRenderer - BufferedImage AWT, Swing, JavaFX & SWT 9
D BufferedImage und Graphics2D AWT, Swing, JavaFX & SWT 3
R Zeichnen von Zahlen in BufferedImage AWT, Swing, JavaFX & SWT 6
G BufferedImage.getRGB() mit 3 int-Werten vergleichen AWT, Swing, JavaFX & SWT 2
Luma BufferedImage wird nicht gezeichnet AWT, Swing, JavaFX & SWT 3
G keine ScaledInstance von BufferedImage? AWT, Swing, JavaFX & SWT 6
S BufferedImage & Scaling: Altes Problem im neuen Gewand AWT, Swing, JavaFX & SWT 2
G zu viele/große BufferedImage führt zu Java heap space AWT, Swing, JavaFX & SWT 5
G BufferedImage und jpg --> maximale Qualität AWT, Swing, JavaFX & SWT 9
F HTML Text irgendwie auf BufferedImage bringen AWT, Swing, JavaFX & SWT 3
R BufferedImage Problem AWT, Swing, JavaFX & SWT 2
G Problem mit BufferedImage und imageIO AWT, Swing, JavaFX & SWT 2
S BufferedImage drehen AWT, Swing, JavaFX & SWT 3
? ActionListener auf BufferedImage AWT, Swing, JavaFX & SWT 11
M BufferedImage mit html interpretierten String beschriften AWT, Swing, JavaFX & SWT 3
A Probelme mit großen BufferedImage in paintComponent AWT, Swing, JavaFX & SWT 7
B Farbtiefe eines BufferedImage verringern AWT, Swing, JavaFX & SWT 3
F ImageIcon -> BufferedImage AWT, Swing, JavaFX & SWT 2
T Performance Problem bei BufferedImage AWT, Swing, JavaFX & SWT 3
F Animiertes Gif als BufferedImage AWT, Swing, JavaFX & SWT 10
L Anzeigen von fotos: ImageIcon oder BufferedImage + paint() ? AWT, Swing, JavaFX & SWT 5
C Rotate BufferedImage --> Bild unvollständig AWT, Swing, JavaFX & SWT 5
U Streifen hinter bewegtem BufferedImage AWT, Swing, JavaFX & SWT 13
M BufferedImage skalieren AWT, Swing, JavaFX & SWT 6
T BufferedImage verkleinern Resultat ist zu pixelig. AWT, Swing, JavaFX & SWT 6
G Image Object speichern oder in ein BufferedImage umwandeln AWT, Swing, JavaFX & SWT 2
P Problem beim Zeichnen auf ein BufferedImage AWT, Swing, JavaFX & SWT 4
B BufferedImage aus einer Datei AWT, Swing, JavaFX & SWT 4
C Farben in BufferedImage ändern ? AWT, Swing, JavaFX & SWT 2
J Image to BufferedImage AWT, Swing, JavaFX & SWT 5
T BufferedImage kopieren AWT, Swing, JavaFX & SWT 3
T BufferedImage Farbe "Transparent" AWT, Swing, JavaFX & SWT 21
T BufferedImage + bestimmten bereich ausfüllen AWT, Swing, JavaFX & SWT 3
M BufferedImage Größe? AWT, Swing, JavaFX & SWT 10
U Löschen eines BufferedImage AWT, Swing, JavaFX & SWT 7
J Image aus BufferedImage ohne AWT AWT, Swing, JavaFX & SWT 5
V Image in BufferedImage AWT, Swing, JavaFX & SWT 3
J BufferedImage aus byte-Array erstellen AWT, Swing, JavaFX & SWT 3
F JavaFX Probleme beim automatischen Konvertieren AWT, Swing, JavaFX & SWT 4
D String zu StringProperty Konvertieren AWT, Swing, JavaFX & SWT 4

Ähnliche Java Themen

Neue Themen


Oben