diff --git a/src/cli_args.rs b/src/cli_args.rs
index a801c193e208002398f89f09f741b7ec50552cdf..82bcf6bee8c587d08c18d6cf0a53b1cb11220c53 100644
--- a/src/cli_args.rs
+++ b/src/cli_args.rs
@@ -3,7 +3,7 @@ use image::ImageFormat;
 use serde::{Deserialize, Serialize};
 
 use crate::commands::{
-	Atlas, Extract, Extrude, Flip, Palette, Pipeline, Reduce, Remap, Rotate, Scale, Split,
+	Atlas, Extract, Extrude, Flip, Info, Palette, Pipeline, Reduce, Remap, Rotate, Scale, Split,
 };
 
 use crate::load_image;
@@ -50,6 +50,9 @@ pub enum Args {
 	#[clap(name = "extract")]
 	#[serde(alias = "extract")]
 	Extract(Extract),
+	#[clap(name = "info")]
+	#[serde(alias = "info")]
+	Info(Info),
 }
 
 impl Args {
@@ -120,6 +123,15 @@ impl Args {
 				let image_data = load_image(&extract.input, None)?;
 				extract.run(&image_data)
 			}
+			Args::Info(info) => {
+				let image_data = load_image(&info.input, None)?;
+				let output = info.run(&image_data)?;
+				{
+					let file = std::fs::File::create(&info.output)?;
+					serde_json::to_writer_pretty(file, &output)?;
+				}
+				Ok(())
+			}
 		}
 	}
 }
diff --git a/src/commands/info.rs b/src/commands/info.rs
new file mode 100644
index 0000000000000000000000000000000000000000..4947ad408acecc64c6fe914256d33cea25b42ae7
--- /dev/null
+++ b/src/commands/info.rs
@@ -0,0 +1,62 @@
+use crate::utils::TypedOutputFormat;
+use clap::{Parser, ValueEnum};
+use image::{imageops, GenericImage, ImageFormat, Pixel};
+use serde::{Deserialize, Serialize};
+
+/// Extract Information About An Image
+#[derive(Debug, Clone, Parser, Serialize, Deserialize)]
+#[clap(author, version = "0.7.0")]
+pub struct Info {
+	/// The path to the image file
+	#[serde(default)]
+	pub input: String,
+	/// The path to write the flipped image
+	#[serde(default)]
+	pub output: String,
+	/// The size of each tile in the spritesheet. Assumed to be square tiles
+	#[clap(short, long, default_value = None)]
+	#[serde(default)]
+	pub tile_size: Option<u32>,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct ImageInfo {
+	image_width: u32,
+	image_height: u32,
+	image_format: String,
+	tile_width: Option<u32>,
+	tile_height: Option<u32>,
+	rows: Option<u32>,
+	columns: Option<u32>,
+}
+
+impl Info {
+	pub fn run<T: GenericImage>(&self, image: &T) -> anyhow::Result<ImageInfo>
+	where
+		T::Pixel: 'static,
+		<T::Pixel as Pixel>::Subpixel: 'static,
+	{
+		let format = ImageFormat::from_path(&self.input)?;
+		let image_width = image.width();
+		let image_height = image.height();
+
+		let mut image_info = ImageInfo {
+			image_width,
+			image_height,
+			image_format: format!("{:?}", format).to_lowercase(),
+			tile_width: None,
+			tile_height: None,
+			rows: None,
+			columns: None,
+		};
+
+		if let Some(tile_size) = self.tile_size {
+			image_info.tile_width = Some(tile_size);
+			image_info.tile_height = Some(tile_size);
+			image_info.rows = Some(image_info.image_height / tile_size);
+			image_info.columns = Some(image_info.image_width / tile_size);
+		}
+
+		Ok(image_info)
+	}
+}
diff --git a/src/commands/mod.rs b/src/commands/mod.rs
index 5a332e27b7793154be0c324e9410198be76b94cf..a3c215c687b8ede2018ceb59bf620ed70e682967 100644
--- a/src/commands/mod.rs
+++ b/src/commands/mod.rs
@@ -2,6 +2,7 @@ mod atlas;
 mod extract;
 mod extrude;
 mod flip;
+mod info;
 mod palette;
 mod pipeline;
 mod reduce;
@@ -14,6 +15,7 @@ pub use atlas::Atlas;
 pub use extract::Extract;
 pub use extrude::Extrude;
 pub use flip::Flip;
+pub use info::Info;
 pub use palette::Palette;
 pub use pipeline::Pipeline;
 pub use reduce::Reduce;