PNG - Dateiformat + Speicherung

Ikaron

Bekanntes Mitglied
Okey, ich möchte ein BufferedImage (Für den Anfang als TYPE_INT_ARGB) speichern mit dem Format "png". Ja, ich kenne ImageIO, aber der Sinn hinter dem ganzen hier ist
1. dass ich lerne, mit DataChunks umzugehen, und den Aufbau von PNG verstehe.
2. dass ich das Ganze auf APNG erweitern kann

Also, ich kann sowohl Signatur als auch IHDR/IEND-Chunks schreiben, das funktioniert auch relativ gut. Nur der IDAT-Chunk bereitet mir Schwierigkeiten. Ich habe ca. 6 PNG-Spezifikationen durchgelesen, diese gehen aber gar nicht oder nur mangelhaft auf den IDAT-Chunk ein. Hierbei benutze ich Testweise eine Bitrate von 8. Wie speichert man nun die Pixel in dem Data-Teil? Ich gehe einfach mal davon aus, dass man den RGB-Wert in ein byte-Array mit vier Plätzen schreibt, und dieses dann komprimiert schreibt. Stimmt das so, bzw. kann mir jemand einen richtigen Ansatz nennen?
Vielen Dank im Voraus,
Ikaron
 

Runtime

Top Contributor
Wenn du ds Bild einfach ohne kompression abspeichern möchtest, dann musst du keinen Filter, Kompressionsalgorithmus oder sonstiges darüberlaufen lassen, sondern einfach nur die vier bytes nacheinander in einem Byte-Array mit Grösse width * height * 4 abspeichern. Beachte, dass du je nach Format auch den Alphakanal abspeichern musst. Wenn du das Bild gut abspeichern willst, dann wirds einiges aufwändiger. Ich kannte mal eine super Spezifikation, finde sie aber nicht mehr und weiss nicht, ob du die schon gelesen hast.
 

Runtime

Top Contributor
Ja. Die Möglichkeit, mehrere IDAT-Chunks abzuspeichern ist dazu da, dass Encoder mit einer fixen Buffergrösse arbeiten können.
 

Ikaron

Bekanntes Mitglied
Gut. Jetzt stellt sich noch die Frage: Muss man die Daten deflaten? Und wenn ja, was für eine Möglichkeit gibt's hier? Ich hab schon ZipOutputStream versucht, der braucht aber ein ZipEntry.. Also die Daten in's ZipEntry und dann über den ZipOutputStream?
Grad hab ich den DeflaterOutputStream gefunden, und werde das mal versuchen...

Ein komplett leeres 200x200 Pixel Bild ergibt folgenden output:
Code:
//PNG-Signatur: 89 50 4E 47 0D 0A 1A 0A 0D
//IHDR: 49 48 44 52 00 00 00 C8 00 00 00 C8 08 06 00 00 00 00 00 00 00 00 //Die letzen 4 bytes sind der CRC Hierbei: Bildgröße 200x200 -> 00 00 00 C8 00 00 00 C8 Bittiefe: 8 Farbmodus oder wie das heißt: 6 (RGB + Alpha ohne Paletten)
//Komprimierter IDAT: 49 44 41 54 00 78 9C 00 00 00 00 00 //Die letzen 4 bytes sind der CRC
//IEND: 49 45 4E 44 00 00 00 00

Was mir da jetzt auffällt:
1. Da steht keine Länge, mal schaun, was da falsch ist.
2. Wie krieg ich die Länge von dem Deflateten? Oder soll ich das deflaten einfach lassen?

€dit: ES GEHT! Ich musste nur die Länge des Chunks als 4-Byte-Integer speichern! Aber ich kann das Bild jetzt öffnen..
 
Zuletzt bearbeitet:

Ikaron

Bekanntes Mitglied
Sorry für doublepost, aber kann den Beitrag nimmer verändern..
Ohne Deflate ist das Bild einfach nur komplett Transparent, deshalb: Wie krieg ich die Länge des gedeflateten Chunks?
 

Runtime

Top Contributor
Wenn du im Header nicht angegeben hast, dass du die Daten komprimierst (vorerst empfohlen), dann darfst du das auch nicht. Von welcher Länge sprichst du? Von der Länge der gedeflateten Daten? Die weiss man erst nach dem komprimieren. Wenn du es nicht selbst schaffst, dann poste mal den Code, den du benutzt hast.
 

Ikaron

Bekanntes Mitglied
Mein Code sieht so aus:
Java:
		DataChunk c = new DataChunk(8);
		c.setData(0, new int[] { 137, 80, 78, 71, 13, 10, 26, 10 });
		c.writeChunk(out);

		SpecifiedChunk c1 = new SpecifiedChunk("IHDR", 13);
		c1.setData(0, Converter.byteArrToIntArr(Converter.intToByteArr(bi
				.getWidth())));
		c1.setData(4, Converter.byteArrToIntArr(Converter.intToByteArr(bi
				.getHeight())));
		c1.setData(8, new int[] { 8, 6, 0, 0, 0 });
		c1.writeChunk(out);

		ZippedChunk c2 = new ZippedChunk("IDAT", bi.getWidth() * bi.getHeight()
				* 4);
		c2.skipFirst();
		c2.setData(0, 0);

		for (int j = 0; j < bi.getHeight(); j++) {

			for (int i = 0; i < bi.getWidth(); i++) {

				int color = bi.getRGB(i, j);
				c2.setData((j * bi.getWidth() * 4) + ((i * 4) + 1), Converter
						.byteArrToIntArr(Converter.intToByteArr(color)));
			}
		}

		c2.writeChunk(out);

		SpecifiedChunk c3 = new SpecifiedChunk("IEND", 0);
		c3.writeChunk(out);
Bei einem "DataChunk" werden nur die Daten selbst geschrieben, bei einem "SpecifiedChunk" auch Chunkname/Länge/Crc, und beim "ZippedChunk" wie beim Specified, nur halt dass die Daten deflated werden.

Solltest du den Deflation-Algorithmus meinen:

Java:
	public void writeChunk(OutputStream out) {

		try {
			out.write(Converter.intToByteArr(getLength()));
			out.write(name.getBytes());
			if (skipFirst)
				out.write(getData()[0]);
			writeZippedData(
					skipFirst ? Converter.subArr(getData(), 1, getData().length)
							: getData(), out);
			out.write(new byte[4]);
		} catch (IOException e) {

			e.printStackTrace();
		}
	}

	private void writeZippedData(byte[] bs, OutputStream out) {

		DeflaterOutputStream dout = new DeflaterOutputStream(out);

		try {
			dout.write(bs);
			dout.flush();
		} catch (IOException e) {

			e.printStackTrace();
		}
	}

Die Länge ist nun aber falsch.. Sollte ich dafür eine TempFile anlegen, nur das zu deflatende reinschreiben, die Größe überprüfen, und diese dann löschen? Wäre ja etwas aufwendig.. Hab das jetzt so gemacht und bekomm auch die richtige Größe, das Bild ist aber immer noch komplett transparent.. Darf man vllt nicht [c]c2.setData((j * bi.getWidth() * 4) + ((i * 4) + 1), Converter.byteArrToIntArr(Converter.intToByteArr(color)));[/c] benutzen? Wenn ja, was ist da falsch?
 
Zuletzt bearbeitet:

Runtime

Top Contributor
:oops: Sorry, mein Fehler, du musst es komprimieren, ich hatte es irgendwie falsch in Erinnerung, so, dass 0 keine Kompressionsmethode ist. Dann stimmt also alles ;). Nutze den Deflater, nicht den DeflaterOutputStream, da kannst du imho einfach ein Byte-Array übergeben und komprimieren lassen.
 
Zuletzt bearbeitet:

Ikaron

Bekanntes Mitglied
Öhm, hast du Skype? -> Add mich (xXIkaron), weil so wird das nix.. Sind so viele einzelne Fragen, wäre sinnvoller hier dann die Lösung zu posten.
Ps: Der Deflater komprimiert das iwie nicht.
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
Tobse Input/Output Dateiformat: Serialisierung VS Custom format Allgemeine Java-Themen 6
E Welches Dateiformat für gespeicherte Einstellungen? Allgemeine Java-Themen 20
M Eigenem Dateiformat Icon zuweisen Allgemeine Java-Themen 6
G eigenes dateiformat als zip Allgemeine Java-Themen 2
B Dateiformat auslesen Allgemeine Java-Themen 8
Jose05 Speicherung auf einem Server Allgemeine Java-Themen 1
J Input/Output Art der Speicherung Allgemeine Java-Themen 1
M Lernende Vektorquantisierung - Implementation und Speicherung Allgemeine Java-Themen 1
MTJ004 FTP Frage zu FTP Speicherung Java-Android-FTP Allgemeine Java-Themen 5
C Speicherung fon Zeile und Spalte Allgemeine Java-Themen 2
M Werte aus DB in Liste speichern ohne mehrfach speicherung Allgemeine Java-Themen 18
X Persistente Speicherung Allgemeine Java-Themen 14
Fu3L Input/Output Brauche Rat bei effizienter Speicherung großer Datenmengen Allgemeine Java-Themen 21
Q Serialisierung / Speicherung Geschwindingkeit & Aktuelle Position Allgemeine Java-Themen 7
S Welche Speicherung von Daten bei Kalendarfunktion der jtable Allgemeine Java-Themen 7
S Speicherung von Daten: Datenbank(sql) oder xml? Allgemeine Java-Themen 9
B Speicherung von Daten, Grundsatzfrage Allgemeine Java-Themen 3
@ [Sicherheit] Speicherung von Keys für Verschlüsselung Allgemeine Java-Themen 4
M Speicherung von Konfigurationsdaten Allgemeine Java-Themen 3
S Speicherung von Configurationen und zugriff auf diese Allgemeine Java-Themen 7

Ähnliche Java Themen


Oben