diff --git a/src/Bitpix.php b/src/Bitpix.php
new file mode 100644
index 0000000..96bf524
--- /dev/null
+++ b/src/Bitpix.php
@@ -0,0 +1,43 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Dumbastro\FitsPhp;
+
+/**
+* Valid BITPIX values
+*/
+enum Bitpix: int
+{
+    case Uint8 = 8;
+    case Uint16 = 16;
+    case Uint32 = 32;
+    case Uint64 = 64;
+    case Float32 = -32;
+    case Float64 = -64;
+
+    public function type(): string
+    {
+        return match($this) {
+            Bitpix::Uint8 => 'int8',
+            Bitpix::Uint16 => 'int16',
+            Bitpix::Uint32 => 'int32',
+            Bitpix::Uint64 => 'int64',
+            Bitpix::Float32 => 'float32',
+            Bitpix::Float64 => 'float64',
+        };
+    }
+
+    public function toString(): string
+    {
+        return match($this) {
+            Bitpix::Uint8 => 'Character or unsigned binary integer',
+            Bitpix::Uint16 => '16 bit two\'s complement binary integer',
+            Bitpix::Uint32 => '32 bit two\'s complement binary integer',
+            Bitpix::Uint64 => '64 bit two\'s complement binary integer',
+            Bitpix::Float32 => 'IEEE single-precision floating point',
+            Bitpix::Float64 => 'IEEE double-precision floating point',
+        };
+    }
+}
+
diff --git a/src/Exceptions/InvalidBitpixValue.php b/src/Exceptions/InvalidBitpixValue.php
new file mode 100644
index 0000000..87edaf8
--- /dev/null
+++ b/src/Exceptions/InvalidBitpixValue.php
@@ -0,0 +1,13 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Dumbastro\FitsPhp\Exceptions;
+
+class InvalidBitpixValue extends \Exception
+{
+    public function __construct(int $bitpix)
+    {
+        $this->message = "The value $bitpix is not a valid BITPIX value";
+    }
+}
diff --git a/src/Exceptions/InvalidFitsException.php b/src/Exceptions/InvalidFits.php
similarity index 51%
rename from src/Exceptions/InvalidFitsException.php
rename to src/Exceptions/InvalidFits.php
index 55a287b..8137187 100644
--- a/src/Exceptions/InvalidFitsException.php
+++ b/src/Exceptions/InvalidFits.php
@@ -4,7 +4,7 @@ declare(strict_types=1);
 
 namespace Dumbastro\FitsPhp\Exceptions;
 
-final class InvalidFitsException extends \Exception implements \Throwable
+final class InvalidFits extends \Exception implements \Throwable
 {
 }
 
diff --git a/src/Exceptions/InvalidPathException.php b/src/Exceptions/InvalidPath.php
similarity index 72%
rename from src/Exceptions/InvalidPathException.php
rename to src/Exceptions/InvalidPath.php
index 8563a0f..88b3bfe 100644
--- a/src/Exceptions/InvalidPathException.php
+++ b/src/Exceptions/InvalidPath.php
@@ -7,6 +7,6 @@ namespace Dumbastro\FitsPhp\Exceptions;
 /**
 * @todo Different exception if path is not writable?
 */
-final class InvalidPathException extends \Exception
+final class InvalidPath extends \Exception
 {
 }
diff --git a/src/Fits.php b/src/Fits.php
index f3d06b6..5e51584 100644
--- a/src/Fits.php
+++ b/src/Fits.php
@@ -5,38 +5,39 @@ declare(strict_types=1);
 namespace Dumbastro\FitsPhp;
 
 use Dumbastro\FitsPhp\Exceptions\{
-    InvalidFitsException,
-    InvalidPathException,
+    InvalidFits,
+    InvalidPath,
 };
 
 class Fits
 {
-    /**
-    * @var resource $byteStream
-    */
-    private $byteStream;
+    private string $contents;
     private string $path;
+    private FitsHeader $fitsHeader;
     public readonly int $size;
     public readonly string $headerBlock;
+    public readonly string $imageBlob;
 
     /**
-    * @throws InvalidFitsException, InvalidPathException
+    * @throws InvalidFits, InvalidPath
     * @todo Check path for reading/writing errors
     */
     public function __construct(string $path)
     {
         if (! is_readable($path) || ! is_file($path)) {
-            throw new InvalidPathException("The path '$path' is not readable or is not a file.");
+            throw new InvalidPath("The path '$path' is not readable or is not a file.");
         }
-        $this->byteStream = fopen($path, 'rb');
+        $this->contents = file_get_contents($path);
         $this->path = $path;
         $this->size = filesize($this->path);
 
         if (! $this->validate()) {
-            throw new InvalidFitsException('The opened file is not a valid FITS image (invalid block size)');
+            throw new InvalidFits('The opened file is not a valid FITS image (invalid block size)');
         }
 
         $this->headerBlock = $this->extractHeader();
+        $this->fitsHeader = new FitsHeader($this->headerBlock);
+        $this->imageBlob = $this->extractImageBlob();
     }
     /**
     * Validate the given FITS file based on block sizes
@@ -66,12 +67,29 @@ class Fits
     */
     private function extractHeader(): string
     {
-        $contents = fread($this->byteStream, $this->size);
-        $end = strpos($contents, 'END');
+        $end = strpos($this->contents, 'END');
         // Determine minimum integer number of blocks including 'END' position
         $headerEnd = (($end - ($end % 2880)) / 2880 + 1) * 2880;
 
-        return substr($contents, 0, $headerEnd);
+        return substr($this->contents, 0, $headerEnd);
+    }
+    /**
+    * Extract the FITS image blob as a string;
+    * it uses the NAXIS1 and NAXIS2 keywords
+    * to compute the length of the main data table
+    */
+    private function extractImageBlob(): string
+    {
+        $naxis1 = (int)trim($this->fitsHeader->getKeywordValue('NAXIS1'));
+        $naxis2 = (int)trim($this->fitsHeader->getKeywordValue('NAXIS2'));
+
+        $blobEnd = $naxis1 * $naxis2;
+
+        return substr(
+            $this->contents,
+            strlen($this->headerBlock) + 1,
+            $blobEnd
+        );
     }
 
     public function writeTo(string $path): void
diff --git a/src/FitsHeader.php b/src/FitsHeader.php
index f36c071..64a08b8 100644
--- a/src/FitsHeader.php
+++ b/src/FitsHeader.php
@@ -71,5 +71,36 @@ class FitsHeader
 
         return $keywordsString . $blanks;
     }
+    /**
+    * Retrieve a Keyword object base on key name
+    */
+    public function keyword(string $key): ?Keyword
+    {
+        $keyword = null;
+
+        foreach ($this->keywords as $k) {
+            if (trim($k->name) === $key) {
+                $keyword = $k;
+                break;
+            }
+        }
+
+        return $keyword;
+    }
+    /**
+    * Note: the keyword key string is case-sensitive
+    */
+    public function getKeywordValue(string $key): string
+    {
+        $value = '';
+        foreach ($this->keywords as $keyword) {
+            if (trim($keyword->name) === $key) {
+                $value = $keyword->value;
+                break;
+            }
+        }
+
+        return $value;
+    }
 }
 
diff --git a/src/ImageBlob.php b/src/ImageBlob.php
new file mode 100644
index 0000000..73192bd
--- /dev/null
+++ b/src/ImageBlob.php
@@ -0,0 +1,51 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Dumbastro\FitsPhp;
+
+use Dumbastro\FitsPhp\Exceptions\InvalidBitpixValue;
+use Dumbastro\FitsPhp\Bitpix;
+
+class ImageBlob
+{
+    private string $blob;
+    private FitsHeader $header;
+    public readonly Bitpix $bitpix;
+    public readonly int $dataBits;
+
+    /**
+    * @throws InvalidBitpixValue
+    * @todo Don't assume that NAXIS = 2...
+    */
+    public function __construct(FitsHeader $header, string $blob)
+    {
+        $this->header = $header;
+        $this->blob = $blob;
+        $bitpix = (int) $this->header->keyword('BITPIX')->value;
+        $this->bitpix = Bitpix::tryFrom($bitpix) ?? throw new InvalidBitpixValue($bitpix);
+        $naxis1 = (int) trim($this->header->keyword('NAXIS1')->value);
+        $naxis2 = (int) trim($this->header->keyword('NAXIS2')->value);
+        $this->dataBits = abs($this->bitpix->value) * $naxis1 * $naxis2;
+    }
+    /**
+    * Returns a generator that yields image data
+    * byte by byte
+    */
+    public function dataBytes(): \Generator
+    {
+        for ($i = 0; $i < strlen($this->blob); $i++) {
+            yield $this->blob[$i];
+        }
+    }
+    /**
+    * Convert to PNG
+    * @todo Manipulate bits and add PNG header to blob??
+    *       Throw exception if gd fails?
+    */
+    public function toPNG(int $quality = -1): bool
+    {
+        $gdImg = imagecreatefromstring($this->blob);
+        return imagepng($gdImg, quality: $quality);
+    }
+}