From 577e197f527c354df53db133cd224aa6d213feee Mon Sep 17 00:00:00 2001 From: Bijan Haney Date: Fri, 3 Mar 2023 18:00:56 -0500 Subject: [PATCH 1/2] make sure custom type is big endian encoded --- .artifact/tree.json | 2 +- rimage/depth_map_raw.go | 32 ++++++++++++++++++++------------ rimage/depth_map_test.go | 5 ----- rimage/image_file.go | 20 +++++++------------- rimage/image_file_test.go | 31 +++++++++++++++++++++++++++++++ 5 files changed, 59 insertions(+), 31 deletions(-) diff --git a/.artifact/tree.json b/.artifact/tree.json index cc839e0306d..39b047cda94 100644 --- a/.artifact/tree.json +++ b/.artifact/tree.json @@ -3881,7 +3881,7 @@ "size": 567 }, "fakeDM.vnd.viam.dep": { - "hash": "4a7dca803d353064c65886fae49c823a", + "hash": "80f3125fe6b7244ea0ca8ab7a27fa866", "size": 424 }, "go_encoded_image.png": { diff --git a/rimage/depth_map_raw.go b/rimage/depth_map_raw.go index de5f4d8b99f..734b7816cd6 100644 --- a/rimage/depth_map_raw.go +++ b/rimage/depth_map_raw.go @@ -19,8 +19,11 @@ import ( const MagicNumIntVersionX = 6363110499870197078 // MagicNumIntViamType is the magic number (as an int) for the custom Viam depth type. -// magic number for ViamCustomType is uint64([]byte("DEPTHMAP")), Little Endian. -const MagicNumIntViamType = 5782988369567958340 +// magic number for ViamCustomType is uint64([]byte("DEPTHMAP")), Big Endian. +const MagicNumIntViamType = 4919426490892632400 + +// MagicNumIntViamTypeLittleEndian is "PAMHTPED" for the ReadDepthMap function which uses LittleEndian to read. +const MagicNumIntViamTypeLittleEndian = 5782988369567958340 func _readNext(r io.Reader) (int64, error) { data := make([]byte, 8) @@ -63,7 +66,7 @@ func ReadDepthMap(r io.Reader) (*DepthMap, error) { switch firstBytes { case MagicNumIntVersionX: // magic number for VERSIONX return readDepthMapVersionX(r) - case MagicNumIntViamType: // magic number for ViamCustomType is int64([]byte("DEPTHMAP")) + case MagicNumIntViamTypeLittleEndian: // magic number for ViamCustomType PAMHTPED (LittleEndian DEPTHMAP) return readDepthMapViam(r) default: return readDepthMapRaw(r, firstBytes) @@ -88,20 +91,25 @@ func readDepthMapRaw(ff io.Reader, firstBytes int64) (*DepthMap, error) { func readDepthMapViam(ff io.Reader) (*DepthMap, error) { f := bufio.NewReader(ff) dm := &DepthMap{} + data := make([]byte, 8) - rawWidth, err := _readNext(f) + _, err := f.Read(data) if err != nil { return nil, errors.Wrapf(err, "could not read vnd.viam.dep width") } + rawWidth := binary.BigEndian.Uint64(data) dm.width = int(rawWidth) - rawHeight, err := _readNext(f) + + _, err = f.Read(data) if err != nil { return nil, errors.Wrapf(err, "could not read vnd.viam.dep height") } + rawHeight := binary.BigEndian.Uint64(data) dm.height = int(rawHeight) + // dump the rest of the bytes in a depth slice datSlice := make([]Depth, dm.height*dm.width) - err = binary.Read(f, binary.LittleEndian, &datSlice) + err = binary.Read(f, binary.BigEndian, &datSlice) if err != nil { return nil, errors.Wrapf(err, "could not read vnd.viam.dep data slice") } @@ -315,20 +323,20 @@ func WriteViamDepthMapTo(img image.Image, out io.Writer) (int64, error) { width := img.Bounds().Dx() height := img.Bounds().Dy() - binary.LittleEndian.PutUint64(buf, uint64(MagicNumIntViamType)) + binary.BigEndian.PutUint64(buf, uint64(MagicNumIntViamType)) n, err := out.Write(buf) totalN += int64(n) if err != nil { return totalN, err } - binary.LittleEndian.PutUint64(buf, uint64(width)) + binary.BigEndian.PutUint64(buf, uint64(width)) n, err = out.Write(buf) totalN += int64(n) if err != nil { return totalN, err } - binary.LittleEndian.PutUint64(buf, uint64(height)) + binary.BigEndian.PutUint64(buf, uint64(height)) n, err = out.Write(buf) totalN += int64(n) if err != nil { @@ -336,18 +344,18 @@ func WriteViamDepthMapTo(img image.Image, out io.Writer) (int64, error) { } switch dm := img.(type) { case *DepthMap: - err = binary.Write(out, binary.LittleEndian, dm.data) // uint16 data + err = binary.Write(out, binary.BigEndian, dm.data) if err != nil { return totalN, err } - totalN += int64(len(dm.data) * 2) + totalN += int64(len(dm.data) * 2) // uint16 data case *image.Gray16: grayBuf := make([]byte, 2) for y := 0; y < height; y++ { for x := 0; x < width; x++ { i := dm.PixOffset(x, y) z := uint16(dm.Pix[i+0])<<8 | uint16(dm.Pix[i+1]) - binary.LittleEndian.PutUint16(grayBuf, z) + binary.BigEndian.PutUint16(grayBuf, z) n, err = out.Write(grayBuf) totalN += int64(n) if err != nil { diff --git a/rimage/depth_map_test.go b/rimage/depth_map_test.go index e8cf55ad202..cbd5a6d2b94 100644 --- a/rimage/depth_map_test.go +++ b/rimage/depth_map_test.go @@ -374,7 +374,6 @@ func TestViamDepthMap(t *testing.T) { func TestDepthMapEncoding(t *testing.T) { m, err := NewDepthMapFromFile(context.Background(), artifact.MustPath("rimage/fakeDM.vnd.viam.dep")) test.That(t, err, test.ShouldBeNil) - // Test values at points of DepthMap // This example DepthMap (fakeDM) was made such that Depth(x,y) = x*y test.That(t, m.Width(), test.ShouldEqual, 20) @@ -385,10 +384,6 @@ func TestDepthMapEncoding(t *testing.T) { test.That(t, testPt2, test.ShouldEqual, 60) // Save DepthMap BYTES to a file - buf := bytes.Buffer{} - err = m.WriteToBuf(&buf) - test.That(t, err, test.ShouldBeNil) - test.That(t, buf.Bytes(), test.ShouldNotBeNil) outDir := testutils.TempDirT(t, "", "rimage") saveTo := outDir + "/grayboard_bytes.vnd.viam.dep" err = WriteRawDepthMapToFile(m, saveTo) diff --git a/rimage/image_file.go b/rimage/image_file.go index a98911dc2f0..07c27f58529 100644 --- a/rimage/image_file.go +++ b/rimage/image_file.go @@ -1,7 +1,6 @@ package rimage import ( - "bufio" "bytes" "context" "encoding/binary" @@ -94,23 +93,18 @@ func init() { }, func(r io.Reader) (image.Config, error) { // Using Gray 16 as underlying color model for depth - f := r.(*bufio.Reader) - firstBytes, err := _readNext(r) - if err != nil || firstBytes != MagicNumIntViamType { - return image.Config{}, errors.Wrap(err, "first image bytes do not match expected magic number") - } - rawWidth, err := _readNext(f) - if err != nil { - return image.Config{}, err - } - rawHeight, err := _readNext(f) + imgBytes := make([]byte, RawDepthHeaderLength) + _, err := io.ReadFull(r, imgBytes) if err != nil { return image.Config{}, err } + header := imgBytes[:RawDepthHeaderLength] + width := binary.BigEndian.Uint64(header[8:16]) + height := binary.BigEndian.Uint64(header[16:24]) return image.Config{ ColorModel: color.Gray16Model, - Width: int(rawWidth), - Height: int(rawHeight), + Width: int(width), + Height: int(height), }, nil }, ) diff --git a/rimage/image_file_test.go b/rimage/image_file_test.go index 69b547c9556..fb29d983dbc 100644 --- a/rimage/image_file_test.go +++ b/rimage/image_file_test.go @@ -85,6 +85,12 @@ func TestRawRGBAEncodingDecoding(t *testing.T) { encodedImgBytes, err := EncodeImage(context.Background(), img, utils.MimeTypeRawRGBA) test.That(t, err, test.ShouldBeNil) + reader := bytes.NewReader(encodedImgBytes) + conf, header, err := image.DecodeConfig(reader) + test.That(t, err, test.ShouldBeNil) + test.That(t, header, test.ShouldEqual, "vnd.viam.rgba") + test.That(t, conf.Width, test.ShouldEqual, img.Bounds().Dx()) + test.That(t, conf.Height, test.ShouldEqual, img.Bounds().Dy()) decodedImg, err := DecodeImage(context.Background(), encodedImgBytes, utils.MimeTypeRawRGBA) test.That(t, err, test.ShouldBeNil) @@ -96,3 +102,28 @@ func TestRawRGBAEncodingDecoding(t *testing.T) { test.That(t, imgB, test.ShouldResemble, decodedImgB) test.That(t, imgA, test.ShouldResemble, decodedImgA) } + +func TestRawDepthEncodingDecoding(t *testing.T) { + img := NewEmptyDepthMap(4, 8) + for x := 0; x < 4; x++ { + for y := 0; y < 8; y++ { + img.Set(x, y, Depth(x*y)) + } + } + encodedImgBytes, err := EncodeImage(context.Background(), img, utils.MimeTypeRawDepth) + test.That(t, err, test.ShouldBeNil) + reader := bytes.NewReader(encodedImgBytes) + conf, header, err := image.DecodeConfig(reader) + test.That(t, err, test.ShouldBeNil) + test.That(t, header, test.ShouldEqual, "vnd.viam.dep") + test.That(t, conf.Width, test.ShouldEqual, img.Bounds().Dx()) + test.That(t, conf.Height, test.ShouldEqual, img.Bounds().Dy()) + + decodedImg, err := DecodeImage(context.Background(), encodedImgBytes, utils.MimeTypeRawDepth) + test.That(t, err, test.ShouldBeNil) + test.That(t, decodedImg.Bounds(), test.ShouldResemble, img.Bounds()) + decodedDm, ok := decodedImg.(*DepthMap) + test.That(t, ok, test.ShouldBeTrue) + test.That(t, decodedDm.GetDepth(2, 3), test.ShouldEqual, img.GetDepth(2, 3)) + test.That(t, decodedDm.GetDepth(1, 0), test.ShouldEqual, img.GetDepth(1, 0)) +} From 4dd81a0858cc323c58b799fc08fb89f7c4e6739b Mon Sep 17 00:00:00 2001 From: Bijan Haney Date: Fri, 3 Mar 2023 18:11:33 -0500 Subject: [PATCH 2/2] more testing --- rimage/image_file_test.go | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/rimage/image_file_test.go b/rimage/image_file_test.go index fb29d983dbc..f43bfcc9331 100644 --- a/rimage/image_file_test.go +++ b/rimage/image_file_test.go @@ -86,12 +86,22 @@ func TestRawRGBAEncodingDecoding(t *testing.T) { encodedImgBytes, err := EncodeImage(context.Background(), img, utils.MimeTypeRawRGBA) test.That(t, err, test.ShouldBeNil) reader := bytes.NewReader(encodedImgBytes) + conf, header, err := image.DecodeConfig(reader) test.That(t, err, test.ShouldBeNil) test.That(t, header, test.ShouldEqual, "vnd.viam.rgba") test.That(t, conf.Width, test.ShouldEqual, img.Bounds().Dx()) test.That(t, conf.Height, test.ShouldEqual, img.Bounds().Dy()) + // decode with image package + reader = bytes.NewReader(encodedImgBytes) + imgDecoded, header, err := image.Decode(reader) + test.That(t, err, test.ShouldBeNil) + test.That(t, header, test.ShouldEqual, "vnd.viam.rgba") + test.That(t, imgDecoded.Bounds(), test.ShouldResemble, img.Bounds()) + test.That(t, imgDecoded.At(3, 6), test.ShouldResemble, img.At(3, 6)) + test.That(t, imgDecoded.At(1, 3), test.ShouldResemble, img.At(1, 3)) + decodedImg, err := DecodeImage(context.Background(), encodedImgBytes, utils.MimeTypeRawRGBA) test.That(t, err, test.ShouldBeNil) test.That(t, decodedImg.Bounds(), test.ShouldResemble, img.Bounds()) @@ -113,12 +123,24 @@ func TestRawDepthEncodingDecoding(t *testing.T) { encodedImgBytes, err := EncodeImage(context.Background(), img, utils.MimeTypeRawDepth) test.That(t, err, test.ShouldBeNil) reader := bytes.NewReader(encodedImgBytes) + + // decode Header conf, header, err := image.DecodeConfig(reader) test.That(t, err, test.ShouldBeNil) test.That(t, header, test.ShouldEqual, "vnd.viam.dep") test.That(t, conf.Width, test.ShouldEqual, img.Bounds().Dx()) test.That(t, conf.Height, test.ShouldEqual, img.Bounds().Dy()) + // decode with image package + reader = bytes.NewReader(encodedImgBytes) + imgDecoded, header, err := image.Decode(reader) + test.That(t, err, test.ShouldBeNil) + test.That(t, header, test.ShouldEqual, "vnd.viam.dep") + test.That(t, imgDecoded.Bounds(), test.ShouldResemble, img.Bounds()) + test.That(t, imgDecoded.At(2, 3), test.ShouldResemble, img.At(2, 3)) + test.That(t, imgDecoded.At(1, 0), test.ShouldResemble, img.At(1, 0)) + + // decode with rimage package decodedImg, err := DecodeImage(context.Background(), encodedImgBytes, utils.MimeTypeRawDepth) test.That(t, err, test.ShouldBeNil) test.That(t, decodedImg.Bounds(), test.ShouldResemble, img.Bounds())