瀏覽代碼

added tiff writer

Nicolas Cannasse 5 年之前
父節點
當前提交
fa4ace4f04
共有 3 個文件被更改,包括 130 次插入14 次删除
  1. 15 1
      hxd/fmt/tiff/Data.hx
  2. 9 13
      hxd/fmt/tiff/Reader.hx
  3. 106 0
      hxd/fmt/tiff/Writer.hx

+ 15 - 1
hxd/fmt/tiff/Data.hx

@@ -21,6 +21,7 @@ enum abstract TifTag(Int) {
 	public inline function new(v) {
 		this = v;
 	}
+	public inline function toInt() return this;
 }
 
 enum abstract TifType(Int) {
@@ -39,6 +40,19 @@ enum abstract TifType(Int) {
 	public inline function new(v) {
 		this = v;
 	}
+	public inline function toInt() return this;
+
+
+	public function getSize() {
+		return switch( new TifType(this) ) {
+		case Byte, Ascii, SByte, UndefByte: 1;
+		case Short, SShort: 2;
+		case Long, SLong, Float: 4;
+		case Rational, SRational, Double: 8;
+		default: throw "assert";
+		}
+	}
+
 }
 
 enum TifValue {
@@ -49,7 +63,7 @@ enum TifValue {
 }
 
 typedef TifFile = {
-	var tags : Array<{ tag : TifTag, value : TifValue }>;
+	var tags : Array<{ tag : TifTag, type : TifType, value : TifValue }>;
 	var data : Array<haxe.io.Bytes>;
 }
 

+ 9 - 13
hxd/fmt/tiff/Reader.hx

@@ -9,16 +9,6 @@ class Reader {
 		this.f = f;
 	}
 
-	static function getTypeSize(t : TifType) {
-		return switch( t ) {
-		case Byte, Ascii, SByte, UndefByte: 1;
-		case Short, SShort: 2;
-		case Long, SLong, Float: 4;
-		case Rational, SRational, Double: 8;
-		default: 0;
-		}
-	}
-
 	public function read() {
 		var order = f.readString(2);
 		f.bigEndian = order == "MM";
@@ -29,18 +19,19 @@ class Reader {
 		var tags = [];
 		while( offset != 0 ) {
 			f.seek(offset, SeekBegin);
-			for( i in 0...f.readUInt16() ) {
+			var count = f.readUInt16();
+			for( i in 0...count ) {
 				var tag = new TifTag(f.readUInt16());
 				var type = new TifType(f.readUInt16());
 				var count = f.readInt32();
 				var next = f.tell();
-				if( count * getTypeSize(type) > 4 ) {
+				if( count * type.getSize() > 4 ) {
 					var offset = f.readInt32();
 					f.seek(offset, SeekBegin);
 				}
 				var value = if( count == 1 || type == Ascii ) readValue(type) else VArray([for( i in 0...count ) readValue(type)]);
 				f.seek(next + 4, SeekBegin);
-				tags.push({ tag : tag, value : value });
+				tags.push({ tag : tag, type : type, value : value });
 			}
 			offset = f.readInt32();
 		}
@@ -53,6 +44,11 @@ class Reader {
 		var offsets = Utils.get(tif, StripOffsets);
 		var bytes = Utils.get(tif, StripByteCounts);
 		if( offsets == null || bytes == null ) throw "Missing image data";
+
+		for( t in tags.copy() )
+			if( t.tag == StripOffsets || t.tag == StripByteCounts )
+				tags.remove(t);
+
 		switch( [offsets,bytes] ) {
 		case [VArray(offsets), VArray(bytes)] if( offsets.length == bytes.length ):
 			for( i in 0...offsets.length )

+ 106 - 0
hxd/fmt/tiff/Writer.hx

@@ -0,0 +1,106 @@
+package hxd.fmt.tiff;
+import hxd.fmt.tiff.Data;
+
+class Writer {
+
+	var f : haxe.io.Output;
+
+	public function new(f) {
+		this.f = f;
+	}
+
+	public function write( tif : TifFile ) {
+		f.writeString("II");
+		f.writeUInt16(42);
+		var pos = 4;
+		var offsets = [], lengths = [];
+		for( d in tif.data ) {
+			offsets.push(pos);
+			lengths.push(d.length);
+			pos += d.length;
+		}
+		f.writeInt32(pos + 4);
+		pos += 4;
+
+		var tags = tif.tags.copy();
+		for( d in tif.data )
+			f.write(d);
+		tags.push({ tag : StripOffsets, type : Long, value : VArray([for( o in offsets ) VInt(o)]) });
+		tags.push({ tag : StripByteCounts, type : Long, value : VArray([for( o in lengths ) VInt(o)]) });
+
+		f.writeUInt16(tags.length);
+		pos += 2;
+
+		var endTags = pos + tags.length * 12 + 4;
+		var tagExtraValues = [];
+
+		for( t in tags ) {
+			f.writeUInt16(t.tag.toInt());
+			f.writeUInt16(t.type.toInt());
+			var count = switch( t.value ) {
+			case VArray(arr): arr.length;
+			case VString(s): s.length;
+			default: 1;
+			}
+			f.writeInt32(count);
+			var size = count * t.type.getSize();
+			if( size > 4 ) {
+				f.writeInt32(endTags);
+				endTags += size;
+				tagExtraValues.push(t);
+			} else {
+				writeValue(t.type, t.value);
+				while( size < 4 ) {
+					f.writeByte(0);
+					size++;
+				}
+			}
+		}
+		f.writeInt32(0);
+
+		for( t in tagExtraValues )
+			writeValue(t.type, t.value);
+
+	}
+
+	function writeValue( t : TifType, v : TifValue ) {
+		switch( [t, v] ) {
+		case [Byte, VInt(v)]:
+			f.writeByte(v);
+		case [Short,VInt(v)]:
+			f.writeUInt16(v);
+		case [Long,VInt(v)]:
+			f.writeInt32(v);
+		case [_, VArray(arr)]:
+			for( v in arr )
+				writeValue(t, v);
+		default:
+			throw "TODO:writeValue "+t+":"+v;
+		}
+	}
+
+
+	public static function ofPixels( pix : hxd.Pixels ) {
+		if( pix.format != R32F ) throw "Format not supported";
+		var tif : TifFile = {
+			tags : [],
+			data : [],
+		};
+		inline function add(t,tp,v) tif.tags.push({ tag : t, type : tp, value : v });
+		add(ImageWidth,Short,VInt(pix.width));
+		add(ImageHeight,Short,VInt(pix.height));
+		add(BitsPerSample,Short,VInt(32));
+		add(Compression,Short,VInt(1));
+		add(PhotometricInterpretation,Short,VInt(1));
+		add(Orientation,Short,VInt(1));
+		add(SamplesPerPixel,Short,VInt(1));
+		add(RowsPerStrip,Short,VInt(1));
+		add(PlanarConfiguration,Short,VInt(1));
+		add(SampleFormat,Short,VInt(3));
+		var lineSize = pix.width * 4;
+		for( i in 0...pix.width )
+			tif.data.push(pix.bytes.sub(pix.offset + i * lineSize, lineSize));
+		return tif;
+	}
+
+}