diff --git a/cz/src/common.rs b/cz/src/common.rs
index 4e3d6e3..edb96ab 100644
--- a/cz/src/common.rs
+++ b/cz/src/common.rs
@@ -213,6 +213,91 @@ impl CzHeader for CommonHeader {
     }
 }
 
+#[derive(Debug, Clone, Copy)]
+pub struct ExtendedHeader {
+    /// Unknown bytes
+    unknown_1: [u8; 5],
+
+    /// Width of cropped image area
+    pub crop_width: u16,
+
+    /// Height of cropped image area
+    pub crop_height: u16,
+
+    /// Bounding box width
+    pub bounds_width: u16,
+
+    /// Bounding box height
+    pub bounds_height: u16,
+
+    /// Offset width
+    pub offset_width: Option<u16>,
+
+    /// Offset height
+    pub offset_height: Option<u16>,
+
+    unknown_2: Option<u32>,
+}
+
+impl ExtendedHeader {
+    pub fn new<T: Seek + ReadBytesExt + Read>(
+        input: &mut T,
+        common_header: &CommonHeader
+    ) -> Result<Self, CzError> {
+        let mut unknown_1 = [0u8; 5];
+        input.read_exact(&mut unknown_1)?;
+
+        let crop_width = input.read_u16::<LittleEndian>()?;
+        let crop_height = input.read_u16::<LittleEndian>()?;
+
+        let bounds_width = input.read_u16::<LittleEndian>()?;
+        let bounds_height = input.read_u16::<LittleEndian>()?;
+
+        let mut offset_width = None;
+        let mut offset_height = None;
+        let mut unknown_2 = None;
+        if common_header.length() > 28 {
+            offset_width = Some(input.read_u16::<LittleEndian>()?);
+            offset_height = Some(input.read_u16::<LittleEndian>()?);
+
+            unknown_2 = Some(input.read_u32::<LittleEndian>()?);
+        }
+
+        Ok(Self {
+            unknown_1,
+
+            crop_width,
+            crop_height,
+
+            bounds_width,
+            bounds_height,
+
+            offset_width,
+            offset_height,
+
+            unknown_2,
+        })
+    }
+
+    pub fn as_bytes(&self) -> Result<Vec<u8>, io::Error> {
+        let mut buf = vec![];
+
+        buf.write_all(&self.unknown_1)?;
+        buf.write_u16::<LittleEndian>(self.crop_width)?;
+        buf.write_u16::<LittleEndian>(self.crop_height)?;
+        buf.write_u16::<LittleEndian>(self.bounds_width)?;
+        buf.write_u16::<LittleEndian>(self.bounds_height)?;
+
+        if self.offset_width.is_some() {
+            buf.write_u16::<LittleEndian>(self.offset_width.unwrap())?;
+            buf.write_u16::<LittleEndian>(self.offset_height.unwrap())?;
+            buf.write_u32::<LittleEndian>(self.unknown_2.unwrap())?;
+        }
+
+        Ok(buf)
+    }
+}
+
 pub fn get_palette<T: Seek + ReadBytesExt + Read>(
     input: &mut T,
     num_colors: usize,
diff --git a/cz/src/dynamic.rs b/cz/src/dynamic.rs
index 9b573d6..094657d 100644
--- a/cz/src/dynamic.rs
+++ b/cz/src/dynamic.rs
@@ -5,12 +5,13 @@ use std::{
 use byteorder::ReadBytesExt;
 
 use crate::{
-    common::{apply_palette, get_palette, CommonHeader, CzError, CzHeader, CzVersion},
+    common::{apply_palette, get_palette, CommonHeader, CzError, CzHeader, CzVersion, ExtendedHeader},
     formats::{cz0, cz1, cz2, cz3, cz4},
 };
 
 pub struct DynamicCz {
     header_common: CommonHeader,
+    header_extended: Option<ExtendedHeader>,
     palette: Option<Vec<[u8; 4]>>,
     bitmap: Vec<u8>,
 }
@@ -45,6 +46,10 @@ impl DynamicCz {
     pub fn decode<T: Seek + ReadBytesExt + Read>(input: &mut T) -> Result<Self, CzError> {
         // Get the header common to all CZ images
         let header_common = CommonHeader::new(input)?;
+        let mut header_extended = None;
+        if header_common.length() > 15 && header_common.version() != CzVersion::CZ2 {
+            header_extended = Some(ExtendedHeader::new(input, &header_common)?);
+        }
         input.seek(SeekFrom::Start(header_common.length() as u64))?;
 
         // Get the color palette if the bit depth is 8 or less
@@ -77,6 +82,7 @@ impl DynamicCz {
 
         Ok(Self {
             header_common,
+            header_extended,
             palette,
             bitmap,
         })
diff --git a/cz/src/formats/cz0.rs b/cz/src/formats/cz0.rs
index 8b1f71a..f39acb1 100644
--- a/cz/src/formats/cz0.rs
+++ b/cz/src/formats/cz0.rs
@@ -1,113 +1,7 @@
-use std::io::{self, Read, Seek, Write};
-use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
+use std::io::{Read, Seek};
+use byteorder::ReadBytesExt;
 
-use crate::common::{CommonHeader, CzError, CzHeader, CzVersion};
-
-#[derive(Debug, Clone, Copy)]
-pub struct Cz0Header {
-    /// Common CZ# header
-    pub common: CommonHeader,
-
-    /// Unknown bytes
-    unknown_1: [u8; 5],
-
-    /// Width of cropped image area
-    pub crop_width: u16,
-
-    /// Height of cropped image area
-    pub crop_height: u16,
-
-    /// Bounding box width
-    pub bounds_width: u16,
-
-    /// Bounding box height
-    pub bounds_height: u16,
-
-    /// Offset width
-    pub offset_width: Option<u16>,
-
-    /// Offset height
-    pub offset_height: Option<u16>,
-
-    unknown_2: Option<[u8; 4]>,
-}
-
-impl Cz0Header {
-    fn new<T: Seek + ReadBytesExt + Read>(bytes: &mut T) -> Result<Self, CzError>
-    where
-        Self: Sized,
-    {
-        let common = CommonHeader::new(bytes)?;
-
-        if common.version() != CzVersion::CZ0 {
-            return Err(CzError::VersionMismatch(common.version() as u8, 0));
-        }
-
-        let mut unknown_1 = [0u8; 5];
-        bytes.read_exact(&mut unknown_1)?;
-
-        let crop_width = bytes.read_u16::<LittleEndian>()?;
-        let crop_height = bytes.read_u16::<LittleEndian>()?;
-
-        let bounds_width = bytes.read_u16::<LittleEndian>()?;
-        let bounds_height = bytes.read_u16::<LittleEndian>()?;
-
-        let mut offset_width = None;
-        let mut offset_height = None;
-        let mut unknown_2 = None;
-        if common.length() > 28 {
-            offset_width = Some(bytes.read_u16::<LittleEndian>()?);
-            offset_height = Some(bytes.read_u16::<LittleEndian>()?);
-
-            let mut un_2 = [0u8; 4];
-            bytes.read_exact(&mut un_2)?;
-
-            unknown_2 = Some(un_2);
-        }
-
-        Ok(Self {
-            common,
-
-            unknown_1,
-
-            crop_width,
-            crop_height,
-
-            bounds_width,
-            bounds_height,
-
-            offset_width,
-            offset_height,
-
-            unknown_2,
-        })
-    }
-
-    fn to_bytes(&self) -> Result<Vec<u8>, io::Error> {
-        let mut buf = vec![];
-
-        buf.write_all(&self.common.to_bytes()?)?;
-        buf.write_all(&self.unknown_1)?;
-        buf.write_u16::<LittleEndian>(self.crop_width)?;
-        buf.write_u16::<LittleEndian>(self.crop_height)?;
-        buf.write_u16::<LittleEndian>(self.bounds_width)?;
-        buf.write_u16::<LittleEndian>(self.bounds_height)?;
-
-        if self.common.length() > 28 {
-            buf.write_u16::<LittleEndian>(self.offset_width.unwrap())?;
-            buf.write_u16::<LittleEndian>(self.offset_height.unwrap())?;
-            buf.write_all(&self.unknown_2.unwrap())?;
-        }
-
-        Ok(buf)
-    }
-}
-
-#[derive(Debug)]
-pub struct Cz0Image {
-    header: Cz0Header,
-    bitmap: Vec<u8>,
-}
+use crate::common::CzError;
 
 pub fn decode<T: Seek + ReadBytesExt + Read>(bytes: &mut T) -> Result<Vec<u8>, CzError> {
     // Get the rest of the file, which is the bitmap