Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions h5g_group.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ package hdf5
import "C"

import (
"errors"
"fmt"
"image"
"unsafe"
)

Expand Down Expand Up @@ -169,3 +171,19 @@ func (g *CommonFG) LinkExists(name string) bool {
defer C.free(unsafe.Pointer(c_name))
return C.H5Lexists(g.id, c_name, 0) > 0
}

// CreateImage create a image(RGB only) set with given name in the receiver.
func (g *CommonFG) CreateImage(name string, img image.Image) error {
if g.LinkExists(name) {
return errors.New("hdf5: name already exist")
}
return newImage(g.id, name, img)
}

// ReadImage read a image dataset, returning it as an image.Image.
func (g *CommonFG) ReadImage(name string) (image.Image, error) {
if !g.LinkExists(name) {
return nil, errors.New("hdf5: name doesn't exist")
}
return getImage(g.id, name)
}
51 changes: 51 additions & 0 deletions h5g_group_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
package hdf5

import (
"image"
"image/color"
"image/jpeg"
"os"
"testing"
)
Expand Down Expand Up @@ -128,3 +131,51 @@ func TestGroup(t *testing.T) {
}

}

func TestImage(t *testing.T) {
f, err := CreateFile(fname, F_ACC_TRUNC)
if err != nil {
t.Fatalf("CreateFile failed: %v", err)
}
defer os.Remove(fname)
defer f.Close()
img := image.NewRGBA(image.Rect(0, 0, 1000, 500))
for y := 200; y < 300; y++ {
for x := 400; x < 600; x++ {
img.Set(x, y, color.RGBA{255, 0, 255, 255})
}
}
if err != nil {
t.Fatalf("image decoding failed: %v", err)
}
g1, err := f.CreateGroup("foo")
if err != nil {
t.Fatalf("couldn't create group: %v", err)
}
defer g1.Close()
err = g1.CreateImage("image", img)
if err != nil {
t.Fatalf("image saving failed: %v", err)
}
imgRead, err := g1.ReadImage("image")
if err != nil {
t.Fatalf("image reading failed: %v", err)
}
gotWidth := imgRead.Bounds().Max.X
gotHeight := imgRead.Bounds().Max.Y
if gotWidth != 1000 || gotHeight != 500 {
t.Errorf("image dimension mismatch: got %dx%d, want:1000x500", gotWidth, gotHeight)
}

imgfile, err := os.Create("img.jpg")
if err != nil {
t.Fatalf("image file creation failed: %v", err)
}
defer os.Remove("img.jpg")
defer imgfile.Close()

err = jpeg.Encode(imgfile, imgRead, nil)
if err != nil {
t.Errorf("unexpected error saving image: %v", err)
}
}
74 changes: 74 additions & 0 deletions h5i_image.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// license that can be found in the LICENSE file.

package hdf5

// #include "hdf5.h"
// #include "hdf5_hl.h"
// #include <stdlib.h>
// #include <string.h>
import "C"

import (
"errors"
"image"
"image/color"
"unsafe"
)

// newImage takes a image object and convert it to a hdf5 format and write to the id node
func newImage(id C.hid_t, name string, img image.Image) error {
width := img.Bounds().Max.X
height := img.Bounds().Max.Y
var c_width, c_height C.hsize_t
c_name := C.CString(name)
defer C.free(unsafe.Pointer(c_name))
var buf []byte
for y := 0; y < height; y++ {
for x := 0; x < width; x++ {
r, g, b, _ := img.At(x, y).RGBA()
buf = append(buf, byte(r>>8), byte(g>>8), byte(b>>8))
}
}
c_width = C.hsize_t(width)
c_height = C.hsize_t(height)
c_image := (*C.uchar)(unsafe.Pointer(&buf[0]))

status := C.H5IMmake_image_24bit(id, c_name, c_width, c_height, C.CString("INTERLACE_PIXEL"), c_image)
if status < 0 {
return errors.New("hdf5: failed to create true color image")
}
return nil
}

//
func getImage(id C.hid_t, name string) (image.Image, error) {
//TODO(zyc-sudo) Should handle interlace and npal better, yet these two are not needed for simple image read and write.
var width, height, planes C.hsize_t
var npals C.hssize_t
var interlace C.char
c_name := C.CString(name)
defer C.free(unsafe.Pointer(c_name))
rc := C.H5IMget_image_info(id, c_name, &width, &height, &planes, &interlace, &npals)
err := h5err(rc)
if err != nil {
return nil, err
}
gbuf := make([]uint8, width*height*planes)
c_image := (*C.uchar)(unsafe.Pointer(&gbuf[0]))
rc = C.H5IMread_image(id, c_name, c_image)

err = h5err(rc)
if err != nil {
return nil, err
}

g_width := int(width)
g_height := int(height)
img := image.NewRGBA(image.Rect(0, 0, g_width, g_height))
for y := 0; y < g_height; y++ {
for x := 0; x < g_width; x++ {
img.Set(x, y, color.RGBA{gbuf[y*g_width*3+x*3], gbuf[y*g_width*3+x*3+1], gbuf[y*g_width*3+x*3+2], 255})
}
}
return img, err
}