github.com/jjjabc/fitsio@v0.0.0-20161215022839-d1807e9e818e/image_test.go (about) 1 // Copyright 2015 The astrogo Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package fitsio 6 7 import ( 8 "fmt" 9 "image" 10 "image/color" 11 "image/draw" 12 "io/ioutil" 13 "math" 14 "os" 15 "reflect" 16 "testing" 17 18 "github.com/astrogo/fitsio/fltimg" 19 ) 20 21 func TestImageRW(t *testing.T) { 22 curdir, err := os.Getwd() 23 if err != nil { 24 t.Fatalf(err.Error()) 25 } 26 defer os.Chdir(curdir) 27 28 workdir, err := ioutil.TempDir("", "go-fitsio-test-") 29 if err != nil { 30 t.Fatalf(err.Error()) 31 } 32 defer os.RemoveAll(workdir) 33 34 err = os.Chdir(workdir) 35 if err != nil { 36 t.Fatalf(err.Error()) 37 } 38 39 for ii, table := range []struct { 40 name string 41 version int 42 cards []Card 43 bitpix int 44 axes []int 45 image interface{} 46 }{ 47 { 48 name: "new.fits", 49 version: 2, 50 cards: []Card{ 51 { 52 "EXTNAME", 53 "primary hdu", 54 "the primary HDU", 55 }, 56 { 57 "EXTVER", 58 2, 59 "the primary hdu version", 60 }, 61 }, 62 bitpix: 8, 63 axes: []int{3, 4}, 64 image: []int8{ 65 0, 1, 2, 3, 66 4, 5, 6, 7, 67 8, 9, 0, 1, 68 }, 69 }, 70 { 71 name: "new.fits", 72 version: 2, 73 cards: []Card{ 74 { 75 "EXTNAME", 76 "primary hdu", 77 "the primary HDU", 78 }, 79 { 80 "EXTVER", 81 2, 82 "the primary hdu version", 83 }, 84 }, 85 bitpix: 16, 86 axes: []int{3, 4}, 87 image: []int16{ 88 0, 1, 2, 3, 89 4, 5, 6, 7, 90 8, 9, 0, 1, 91 }, 92 }, 93 { 94 name: "new.fits", 95 version: 2, 96 cards: []Card{ 97 { 98 "EXTNAME", 99 "primary hdu", 100 "the primary HDU", 101 }, 102 { 103 "EXTVER", 104 2, 105 "the primary hdu version", 106 }, 107 }, 108 bitpix: 32, 109 axes: []int{3, 4}, 110 image: []int32{ 111 0, 1, 2, 3, 112 4, 5, 6, 7, 113 8, 9, 0, 1, 114 }, 115 }, 116 { 117 name: "new.fits", 118 version: 2, 119 cards: []Card{ 120 { 121 "EXTNAME", 122 "primary hdu", 123 "the primary HDU", 124 }, 125 { 126 "EXTVER", 127 2, 128 "the primary hdu version", 129 }, 130 }, 131 bitpix: 64, 132 axes: []int{3, 4}, 133 image: []int64{ 134 0, 1, 2, 3, 135 4, 5, 6, 7, 136 8, 9, 0, 1, 137 }, 138 }, 139 { 140 name: "new.fits", 141 version: 2, 142 cards: []Card{ 143 { 144 "EXTNAME", 145 "primary hdu", 146 "the primary HDU", 147 }, 148 { 149 "EXTVER", 150 2, 151 "the primary hdu version", 152 }, 153 }, 154 bitpix: -32, 155 axes: []int{3, 4}, 156 image: []float32{ 157 0, 1, 2, 3, 158 4, 5, 6, 7, 159 8, 9, 0, 1, 160 }, 161 }, 162 { 163 name: "new.fits", 164 version: 2, 165 cards: []Card{ 166 { 167 "EXTNAME", 168 "primary hdu", 169 "the primary HDU", 170 }, 171 { 172 "EXTVER", 173 2, 174 "the primary hdu version", 175 }, 176 }, 177 bitpix: -64, 178 axes: []int{3, 4}, 179 image: []float64{ 180 0, 1, 2, 3, 181 4, 5, 6, 7, 182 8, 9, 0, 1, 183 }, 184 }, 185 } { 186 fname := fmt.Sprintf("%03d_%s", ii, table.name) 187 for i := 0; i < 2; i++ { 188 func(i int) { 189 var f *File 190 var w *os.File 191 var r *os.File 192 var err error 193 var hdu HDU 194 195 switch i { 196 197 case 0: // create 198 //fmt.Printf("========= create [%s]....\n", fname) 199 w, err = os.Create(fname) 200 if err != nil { 201 t.Fatalf("error creating new file [%v]: %v", fname, err) 202 } 203 defer w.Close() 204 205 f, err = Create(w) 206 if err != nil { 207 t.Fatalf("error creating new file [%v]: %v", fname, err) 208 } 209 defer f.Close() 210 211 img := NewImage(table.bitpix, table.axes) 212 defer img.Close() 213 214 err = img.Header().Append(table.cards...) 215 if err != nil { 216 t.Fatalf("error appending cards: %v", err) 217 } 218 hdu = img 219 220 err = img.Write(&table.image) 221 if err != nil { 222 t.Fatalf("error writing image: %v", err) 223 } 224 225 err = f.Write(img) 226 if err != nil { 227 t.Fatalf("error writing image: %v", err) 228 } 229 230 case 1: // read 231 //fmt.Printf("========= read [%s]....\n", fname) 232 r, err = os.Open(fname) 233 if err != nil { 234 t.Fatalf("error opening file [%v]: %v", fname, err) 235 } 236 defer r.Close() 237 f, err = Open(r) 238 if err != nil { 239 t.Fatalf("error opening file [%v]: %v", fname, err) 240 } 241 defer f.Close() 242 243 hdu = f.HDU(0) 244 hdr := hdu.Header() 245 img := hdu.(Image) 246 nelmts := 1 247 for _, axe := range hdr.Axes() { 248 nelmts *= int(axe) 249 } 250 251 var data interface{} 252 switch hdr.Bitpix() { 253 case 8: 254 v := make([]int8, 0, nelmts) 255 err = img.Read(&v) 256 data = v 257 258 case 16: 259 v := make([]int16, 0, nelmts) 260 err = img.Read(&v) 261 data = v 262 263 case 32: 264 v := make([]int32, 0, nelmts) 265 err = img.Read(&v) 266 data = v 267 268 case 64: 269 v := make([]int64, 0, nelmts) 270 err = img.Read(&v) 271 data = v 272 273 case -32: 274 v := make([]float32, 0, nelmts) 275 err = img.Read(&v) 276 data = v 277 278 case -64: 279 v := make([]float64, 0, nelmts) 280 err = img.Read(&v) 281 data = v 282 } 283 284 if err != nil { 285 t.Fatalf("error reading image: %v", err) 286 } 287 288 if !reflect.DeepEqual(data, table.image) { 289 t.Fatalf("expected image:\nref=%v\ngot=%v", table.image, data) 290 } 291 } 292 293 hdr := hdu.Header() 294 if hdr.bitpix != table.bitpix { 295 t.Fatalf("expected BITPIX=%v. got %v", table.bitpix, hdr.bitpix) 296 } 297 298 if !reflect.DeepEqual(hdr.Axes(), table.axes) { 299 t.Fatalf("expected AXES==%v. got %v (i=%v)", table.axes, hdr.Axes(), i) 300 } 301 302 name := hdu.Name() 303 if name != "primary hdu" { 304 t.Fatalf("expected EXTNAME==%q. got %q", "primary hdu", name) 305 } 306 307 vers := hdu.Version() 308 if vers != table.version { 309 t.Fatalf("expected EXTVER==%v. got %v", table.version, vers) 310 } 311 312 card := hdr.Get("EXTNAME") 313 if card == nil { 314 t.Fatalf("error retrieving card [EXTNAME]") 315 } 316 if card.Comment != "the primary HDU" { 317 t.Fatalf("expected EXTNAME.Comment==%q. got %q", "the primary HDU", card.Comment) 318 } 319 320 card = hdr.Get("EXTVER") 321 if card == nil { 322 t.Fatalf("error retrieving card [EXTVER]") 323 } 324 if card.Comment != "the primary hdu version" { 325 t.Fatalf("expected EXTVER.Comment==%q. got %q", "the primary hdu version", card.Comment) 326 327 } 328 329 for _, ref := range table.cards { 330 card := hdr.Get(ref.Name) 331 if card == nil { 332 t.Fatalf("error retrieving card [%v]", ref.Name) 333 } 334 rv := reflect.ValueOf(ref.Value) 335 var val interface{} 336 switch rv.Type().Kind() { 337 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 338 val = int(rv.Int()) 339 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: 340 val = int(rv.Uint()) 341 case reflect.Float32, reflect.Float64: 342 val = rv.Float() 343 case reflect.Complex64, reflect.Complex128: 344 val = rv.Complex() 345 case reflect.String: 346 val = ref.Value.(string) 347 } 348 if !reflect.DeepEqual(card.Value, val) { 349 t.Fatalf( 350 "card %q. expected [%v](%T). got [%v](%T)", 351 ref.Name, 352 val, val, 353 card.Value, card.Value, 354 ) 355 } 356 if card.Comment != ref.Comment { 357 t.Fatalf("card %q. comment differ. expected %q. got %q", ref.Name, ref.Comment, card.Comment) 358 } 359 } 360 361 card = hdr.Get("NOT THERE") 362 if card != nil { 363 t.Fatalf("expected no card. got [%v]", card) 364 } 365 }(i) 366 } 367 } 368 } 369 370 func TestImageImage(t *testing.T) { 371 const ( 372 w = 20 373 h = 20 374 ) 375 var ( 376 rect = image.Rect(0, 0, w, h) 377 ) 378 set := func(img draw.Image) { 379 img.Set(0, 0, color.RGBA{255, 0, 0, 255}) 380 img.Set(10, 10, color.RGBA{0, 255, 0, 255}) 381 img.Set(15, 15, color.RGBA{0, 0, 255, 255}) 382 } 383 384 for i, test := range []struct { 385 want image.Image 386 bitpix int 387 }{ 388 { 389 want: func() image.Image { 390 img := image.NewGray(rect) 391 set(img) 392 return img 393 }(), 394 bitpix: 8, 395 }, 396 { 397 want: func() image.Image { 398 img := image.NewGray16(rect) 399 set(img) 400 return img 401 }(), 402 bitpix: 16, 403 }, 404 { 405 want: func() image.Image { 406 img := image.NewRGBA(rect) 407 set(img) 408 return img 409 }(), 410 bitpix: 32, 411 }, 412 { 413 want: func() image.Image { 414 img := image.NewRGBA64(rect) 415 set(img) 416 return img 417 }(), 418 bitpix: 64, 419 }, 420 { 421 want: func() image.Image { 422 pix := image.NewRGBA(rect) 423 set(pix) 424 img := fltimg.NewGray32(rect, pix.Pix) 425 return img 426 }(), 427 bitpix: -32, 428 }, 429 { 430 want: func() image.Image { 431 pix := image.NewRGBA64(rect) 432 set(pix) 433 img := fltimg.NewGray64(rect, pix.Pix) 434 return img 435 }(), 436 bitpix: -64, 437 }, 438 } { 439 hdu := NewImage(test.bitpix, []int{w, h}) 440 switch test.bitpix { 441 case 8: 442 img := test.want.(*image.Gray) 443 err := hdu.Write(&img.Pix) 444 if err != nil { 445 t.Errorf("image #%d: error writing raw pixels: %v\n", i, err) 446 continue 447 } 448 case 16: 449 img := test.want.(*image.Gray16) 450 pix := make([]int16, len(img.Pix)/2) 451 for i := 0; i < len(img.Pix); i += 2 { 452 buf := img.Pix[i : i+2] 453 pix[i/2] = int16(uint16(buf[1]) | uint16(buf[0])<<8) 454 } 455 err := hdu.Write(&pix) 456 if err != nil { 457 t.Errorf("image #%d: error writing raw pixels: %v\n", i, err) 458 continue 459 } 460 case 32: 461 img := test.want.(*image.RGBA) 462 pix := make([]int32, len(img.Pix)/4) 463 for i := 0; i < len(img.Pix); i += 4 { 464 buf := img.Pix[i : i+4] 465 pix[i/4] = int32(uint32(buf[3]) | uint32(buf[2])<<8 | uint32(buf[1])<<16 | uint32(buf[0])<<24) 466 } 467 err := hdu.Write(&pix) 468 if err != nil { 469 t.Errorf("image #%d: error writing raw pixels: %v\n", i, err) 470 continue 471 } 472 case 64: 473 img := test.want.(*image.RGBA64) 474 pix := make([]int64, len(img.Pix)/8) 475 for i := 0; i < len(img.Pix); i += 8 { 476 buf := img.Pix[i : i+8] 477 pix[i/8] = int64(uint64(buf[7]) | uint64(buf[6])<<8 | uint64(buf[5])<<16 | uint64(buf[4])<<24 | 478 uint64(buf[3])<<32 | uint64(buf[2])<<40 | uint64(buf[1])<<48 | uint64(buf[0])<<56) 479 } 480 err := hdu.Write(&pix) 481 if err != nil { 482 t.Errorf("image #%d: error writing raw pixels: %v\n", i, err) 483 continue 484 } 485 case -32: 486 img := test.want.(*fltimg.Gray32) 487 pix := make([]float32, len(img.Pix)/4) 488 for i := 0; i < len(img.Pix); i += 4 { 489 buf := img.Pix[i : i+4] 490 pix[i/4] = math.Float32frombits(uint32(buf[3]) | uint32(buf[2])<<8 | uint32(buf[1])<<16 | uint32(buf[0])<<24) 491 } 492 err := hdu.Write(&pix) 493 if err != nil { 494 t.Errorf("image #%d: error writing raw pixels: %v\n", i, err) 495 continue 496 } 497 case -64: 498 img := test.want.(*fltimg.Gray64) 499 pix := make([]float64, len(img.Pix)/8) 500 for i := 0; i < len(img.Pix); i += 8 { 501 buf := img.Pix[i : i+8] 502 pix[i/8] = math.Float64frombits(uint64(buf[7]) | uint64(buf[6])<<8 | uint64(buf[5])<<16 | uint64(buf[4])<<24 | 503 uint64(buf[3])<<32 | uint64(buf[2])<<40 | uint64(buf[1])<<48 | uint64(buf[0])<<56) 504 } 505 err := hdu.Write(&pix) 506 if err != nil { 507 t.Errorf("image #%d: error writing raw pixels: %v\n", i, err) 508 continue 509 } 510 default: 511 t.Errorf("image #%d: invalid bitpix=%d", i, test.bitpix) 512 continue 513 } 514 if !reflect.DeepEqual(hdu.Image(), test.want) { 515 t.Errorf("image #%d:\n got: %v\nwant: %v\n", i, hdu.Image(), test.want) 516 continue 517 } 518 } 519 520 for i, test := range []struct { 521 bitpix int 522 axes []int 523 want image.Image 524 }{ 525 { 526 bitpix: 0, 527 axes: nil, 528 }, 529 { 530 bitpix: 0, 531 axes: []int{}, 532 }, 533 { 534 bitpix: 0, 535 axes: []int{1}, 536 }, 537 { 538 bitpix: 0, 539 axes: []int{0, 0}, 540 }, 541 { 542 bitpix: 8, 543 axes: nil, 544 }, 545 { 546 bitpix: 8, 547 axes: []int{}, 548 }, 549 { 550 bitpix: 8, 551 axes: []int{1}, 552 }, 553 { 554 bitpix: 8, 555 axes: []int{0, 0}, 556 }, 557 } { 558 hdu := NewImage(test.bitpix, test.axes) 559 img := hdu.Image() 560 if img != test.want { 561 t.Errorf("image #%d:\n got: %v\nwant: %v\n", i, img, test.want) 562 continue 563 } 564 } 565 566 func() { 567 defer func() { 568 if e := recover(); e == nil { 569 t.Errorf("error: expected a BITPIX-related panic") 570 } 571 }() 572 573 hdu := NewImage(0, []int{1, 1}) 574 _ = hdu.Image() 575 }() 576 }