add support for png images
parent
cf0ed6f13f
commit
927f63adf0
@ -0,0 +1,130 @@
|
|||||||
|
package eu.jonahbauer.raytracing.render;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.zip.CRC32;
|
||||||
|
import java.util.zip.CheckedOutputStream;
|
||||||
|
import java.util.zip.DeflaterOutputStream;
|
||||||
|
|
||||||
|
public enum ImageFormat {
|
||||||
|
PPM {
|
||||||
|
@Override
|
||||||
|
public void write(@NotNull Image image, @NotNull OutputStream out) throws IOException {
|
||||||
|
try (var writer = new BufferedWriter(new OutputStreamWriter(out, StandardCharsets.US_ASCII))) {
|
||||||
|
writer.write("P3\n");
|
||||||
|
writer.write(String.valueOf(image.width()));
|
||||||
|
writer.write(" ");
|
||||||
|
writer.write(String.valueOf(image.height()));
|
||||||
|
writer.write("\n255\n");
|
||||||
|
|
||||||
|
var it = image.pixels().iterator();
|
||||||
|
while (it.hasNext()) {
|
||||||
|
var color = it.next();
|
||||||
|
writer.write(String.valueOf(color.red()));
|
||||||
|
writer.write(" ");
|
||||||
|
writer.write(String.valueOf(color.green()));
|
||||||
|
writer.write(" ");
|
||||||
|
writer.write(String.valueOf(color.blue()));
|
||||||
|
writer.write("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
PNG {
|
||||||
|
private static final byte[] MAGIC = new byte[] { (byte) 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A };
|
||||||
|
private static final int IHDR_LENGTH = 13;
|
||||||
|
private static final int IHDR_TYPE = 0x49484452;
|
||||||
|
private static final int IDAT_TYPE = 0x49444154;
|
||||||
|
private static final int IEND_TYPE = 0x49454E44;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(@NotNull Image image, @NotNull OutputStream out) throws IOException {
|
||||||
|
try (var data = new NoCloseDataOutputStream(out); var _ = data.closeable()) {
|
||||||
|
data.write(MAGIC);
|
||||||
|
|
||||||
|
writeIHDR(image, data);
|
||||||
|
writeIDAT(image, data);
|
||||||
|
writeIEND(image, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeIHDR(@NotNull Image image, @NotNull DataOutputStream data) throws IOException {
|
||||||
|
data.writeInt(IHDR_LENGTH);
|
||||||
|
try (
|
||||||
|
var crc = new CheckedOutputStream(data, new CRC32());
|
||||||
|
var ihdr = new DataOutputStream(crc)
|
||||||
|
) {
|
||||||
|
ihdr.writeInt(IHDR_TYPE);
|
||||||
|
ihdr.writeInt(image.width()); // image width
|
||||||
|
ihdr.writeInt(image.height()); // image height
|
||||||
|
ihdr.writeByte(8); // bit depth
|
||||||
|
ihdr.writeByte(2); // color type
|
||||||
|
ihdr.writeByte(0); // compression method
|
||||||
|
ihdr.writeByte(0); // filter method
|
||||||
|
ihdr.writeByte(0); // interlace method
|
||||||
|
ihdr.flush();
|
||||||
|
data.writeInt((int) crc.getChecksum().getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeIDAT(@NotNull Image image, @NotNull DataOutputStream data) throws IOException {
|
||||||
|
try (
|
||||||
|
var baos = new ByteArrayOutputStream();
|
||||||
|
var crc = new CheckedOutputStream(baos, new CRC32());
|
||||||
|
var idat = new DataOutputStream(crc)
|
||||||
|
) {
|
||||||
|
idat.writeInt(IDAT_TYPE);
|
||||||
|
|
||||||
|
try (var deflate = new DataOutputStream(new DeflaterOutputStream(idat))) {
|
||||||
|
var pixels = image.pixels().iterator();
|
||||||
|
for (int i = 0; pixels.hasNext(); i = (i + 1) % image.width()) {
|
||||||
|
if (i == 0) deflate.writeByte(0); // filter type
|
||||||
|
var pixel = pixels.next();
|
||||||
|
deflate.writeByte(pixel.red());
|
||||||
|
deflate.writeByte(pixel.green());
|
||||||
|
deflate.writeByte(pixel.blue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var bytes = baos.toByteArray();
|
||||||
|
data.writeInt(bytes.length);
|
||||||
|
data.write(bytes);
|
||||||
|
data.writeInt((int) crc.getChecksum().getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeIEND(@NotNull Image image, @NotNull DataOutputStream data) throws IOException {
|
||||||
|
data.writeInt(0);
|
||||||
|
data.writeInt(IEND_TYPE);
|
||||||
|
data.writeInt(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class NoCloseDataOutputStream extends DataOutputStream {
|
||||||
|
public NoCloseDataOutputStream(OutputStream out) {
|
||||||
|
super(out);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
public Closeable closeable() {
|
||||||
|
return super::close;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
;
|
||||||
|
|
||||||
|
public void write(@NotNull Image image, @NotNull Path path) throws IOException {
|
||||||
|
try (var out = Files.newOutputStream(path)) {
|
||||||
|
write(image, out);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract void write(@NotNull Image image, @NotNull OutputStream out) throws IOException;
|
||||||
|
}
|
@ -1,34 +0,0 @@
|
|||||||
package eu.jonahbauer.raytracing.render;
|
|
||||||
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
|
|
||||||
public final class ImageIO {
|
|
||||||
private ImageIO() {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void write(@NotNull Image image, @NotNull Path path) throws IOException {
|
|
||||||
try (var out = Files.newBufferedWriter(path)) {
|
|
||||||
out.write("P3\n");
|
|
||||||
out.write(String.valueOf(image.width()));
|
|
||||||
out.write(" ");
|
|
||||||
out.write(String.valueOf(image.height()));
|
|
||||||
out.write("\n255\n");
|
|
||||||
|
|
||||||
var it = image.pixels().iterator();
|
|
||||||
while (it.hasNext()) {
|
|
||||||
var color = it.next();
|
|
||||||
out.write(String.valueOf(color.red()));
|
|
||||||
out.write(" ");
|
|
||||||
out.write(String.valueOf(color.green()));
|
|
||||||
out.write(" ");
|
|
||||||
out.write(String.valueOf(color.blue()));
|
|
||||||
out.write("\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue