Repository: ezrec/uv3dp
Pull request #60 (2020-05-26 23:42:17)

Correct issues with PHZ RLE encoding/decoding
This is a true 7-bit format, not a 5 bit format as I had assumed from my initial test data.


Patch:
diff --git a/phz/format.go b/phz/format.go
index 488d090..f361f57 100644
--- a/phz/format.go
+++ b/phz/format.go
@@ -105,11 +105,6 @@ type Phz struct {
 	rleMap map[uint32]([]byte)
 }
 
-func align4(in uint32) (out uint32) {
-	out = (in + 0x3) & 0xfffffffc
-	return
-}
-
 type PhzFormatter struct {
 	*pflag.FlagSet
 
@@ -245,7 +240,7 @@ func (pf *PhzFormatter) Encode(writer uv3dp.Writer, p uv3dp.Printable) (err erro
 		if !ok {
 			rleHash[info.Hash] = rleInfo{offset: imageBase, rle: info.Rle}
 			rleHashList = append(rleHashList, info.Hash)
-			imageBase = align4(imageBase + uint32(len(info.Rle)))
+			imageBase = imageBase + uint32(len(info.Rle))
 		}
 
 		layerDef[n] = phzLayerDef{
diff --git a/phz/rle.go b/phz/rle.go
index fdb23ed..ec28938 100644
--- a/phz/rle.go
+++ b/phz/rle.go
@@ -60,8 +60,8 @@ func rleEncodeGraymap(bm image.Image) (rle []byte, hash uint64, bitsOn uint) {
 		for x := 0; x < size.X; x++ {
 			c := bm.At(base.X+x, base.Y+y)
 			r, g, b, _ := c.RGBA()
-			// Only 5 bits per pixel
-			grey7 = uint8(uint16(r|g|b)>>9) & 0x7c
+			// 7 bits per pixel
+			grey7 = uint8(uint16(r|g|b)>>9) & 0x7f
 
 			switch {
 			case color == 0xff:
@@ -94,14 +94,8 @@ func rleDecodeGraymap(bounds image.Rectangle, rle []byte) (gm *image.Gray, err e
 	for n := 0; n < len(rle); n++ {
 		code := rle[n]
 		if (code & 0x80) == 0x80 {
-
-			// Convert from 5bpp to 8bpp
-			lastColor = ((code & 0x7c) << 1)
-			// Extend the lower bits
-			if (lastColor & 0x08) != 0 {
-				lastColor |= 0x7
-			}
-
+			// Convert from 7bpp to 8bpp (extending the last bit)
+			lastColor = ((code & 0x7f) << 1) | (code & 1)
 			if index < limit {
 				pix[index] = lastColor
 			}


Test patch:
diff --git a/phz/rle_test.go b/phz/rle_test.go
index 30c1e70..4e80347 100644
--- a/phz/rle_test.go
+++ b/phz/rle_test.go
@@ -36,20 +36,20 @@ func TestRleEncodeGraymap(t *testing.T) {
 	}
 
 	out_rle := []byte{
-		0xfc, 0x3, 0xfc, 0x3, 0x80, 0x3, 0x80, 0x3,
-		0xfc, 0x3, 0xfc, 0x3, 0xfc, 0x3, 0xfc, 0x3,
-		0xfc, 0x3, 0xfc, 0x3, 0xfc, 0x3, 0xfc, 0x3,
-		0xfc, 0x3, 0xfc, 0x3, 0xfc, 0x3, 0xfc, 0x3,
-		0xfc, 0x3, 0xfc, 0x3, 0xfc, 0x3, 0xfc, 0x3,
-		0xfc, 0x3, 0xfc, 0x3, 0xfc, 0x3, 0xfc, 0x3,
-		0xfc, 0x3, 0xfc, 0x3, 0xfc, 0x3, 0xfc, 0x3,
-		0xfc, 0x3, 0xfc, 0x3, 0xfc, 0x3, 0xfc, 0x3,
-		0xfc, 0x3, 0xfc, 0x3, 0xfc, 0x3, 0xfc, 0x3,
-		0xfc, 0x3, 0xfc, 0x80, 0x1, 0xfc, 0xfc, 0x80,
-		0xfc, 0x80, 0xfc, 0x80, 0xfc, 0x80, 0x80, 0x3, 0x80, 0x3,
+		0xff, 0x3, 0xff, 0x3, 0x80, 0x3, 0x80, 0x3,
+		0xff, 0x3, 0xff, 0x3, 0xff, 0x3, 0xff, 0x3,
+		0xff, 0x3, 0xff, 0x3, 0xff, 0x3, 0xff, 0x3,
+		0xff, 0x3, 0xff, 0x3, 0xff, 0x3, 0xff, 0x3,
+		0xff, 0x3, 0xff, 0x3, 0xff, 0x3, 0xff, 0x3,
+		0xff, 0x3, 0xff, 0x3, 0xff, 0x3, 0xff, 0x3,
+		0xff, 0x3, 0xff, 0x3, 0xff, 0x3, 0xff, 0x3,
+		0xff, 0x3, 0xff, 0x3, 0xff, 0x3, 0xff, 0x3,
+		0xff, 0x3, 0xff, 0x3, 0xff, 0x3, 0xff, 0x3,
+		0xff, 0x3, 0xff, 0x80, 0x1, 0xff, 0xff, 0x80,
+		0xff, 0x80, 0xff, 0x80, 0xff, 0x80, 0x80, 0x3, 0x80, 0x3,
 	}
 
-	out_hash := uint64(0xb323ff9e2d9a0478)
+	out_hash := uint64(0x987930520768f61a)
 	out_bits := uint(146)
 
 	rle, hash, bits := rleEncodeGraymap(gray)
diff --git a/uvj/uvj2uvj_test.go b/uvj/uvj2uvj_test.go
index 6e8e6d4..abba69a 100644
--- a/uvj/uvj2uvj_test.go
+++ b/uvj/uvj2uvj_test.go
@@ -78,8 +78,6 @@ func TestUVJToUVJ(t *testing.T) {
 		}
 
 		if uvj_ok {
-			t.Logf("%+v: %v %+v", code, uvj_ok, uvj_prev.Bounds())
-
 			if uvj_prev.Bounds() != out_prev.Bounds() {
 				t.Errorf("%+v: expected bounds %+v, got %+v", code, uvj_prev.Bounds(), out_prev.Bounds())
 				continue