# Image metadata and applied 2D charting Two pragmatic corners of 2D work round out the toolkit arc. First, reading the data already inside image files: dimensions, format, and the EXIF block a camera writes. Second, the most common reason people draw at all, which is turning numbers into a chart. Neither is glamorous, and both come up constantly. ## Reading metadata: Image::Info Before you draw on or resize an image, you often just need to know about it: how big is it, what format, what did the camera record. `Image::Info` is pure Perl, reads the headers without decoding the whole image, and returns a plain hash reference. ```perl use Image::Info qw(image_info dim); my $info = image_info('photo.jpg'); die $info->{error} if $info->{error}; my ($w, $h) = dim($info); print "format: $info->{file_media_type}\n"; # image/jpeg print "size: ${w}x${h}\n"; print "created: $info->{DateTime}\n" if $info->{DateTime}; ``` `dim` is a convenience that pulls width and height out of the hash. The rest of the keys depend on the format and on what the file carries: resolution, color type, and the common EXIF fields for photographs. For a quick «what is this file» it is all you need, and it costs almost nothing because it never decodes the pixels. ## Reading and writing metadata: Image::ExifTool When you need the full metadata surface, and especially when you need to **write** it, `Image::ExifTool` is the definitive tool. It handles the metadata of essentially every image and media format, reads thousands of tags, and can edit them in place without touching the image data. ```perl use Image::ExifTool qw(:Public); my $et = Image::ExifTool->new; $et->ExtractInfo('photo.jpg'); my $model = $et->GetValue('Model'); # camera model my $when = $et->GetValue('DateTimeOriginal'); print "shot on $model at $when\n" if $model; # rewrite a tag and save $et->SetNewValue('Artist' => 'Jane Doe'); $et->WriteInfo('photo.jpg'); # edits metadata only ``` `Image::Info` answers «how big, what format» cheaply; `Image::ExifTool` is the one to reach for when the metadata itself is the job (stripping location tags for privacy, batch-tagging a photo library, reading maker-note fields). Both leave the pixels alone. ## Charting: the honest state of the art Charting is applied 2D drawing: axes, bars, lines, and labels composed from the primitives you already know. The Perl charting landscape is thinner than it once was. Several once-popular modules are now unmaintained, so this section leads with what still works and names the rest plainly. ### GD::Graph for quick raster charts `GD::Graph` builds on `GD` and is still maintained. It is the shortest path to a bar, line, or pie chart as a PNG. You give it data as a set of parallel arrays (the first is the x labels, the rest are data series) and it renders. ```perl use GD::Graph::bars; my @data = ( ['Jan', 'Feb', 'Mar', 'Apr'], # x-axis labels [ 12, 19, 8, 23 ], # one data series ); my $chart = GD::Graph::bars->new(400, 300); $chart->set( title => 'Widgets shipped', y_max_value => 25, dclrs => ['blue'], ) or die $chart->error; my $gd = $chart->plot(\@data) or die $chart->error; open my $fh, '>', 'chart.png' or die $!; binmode $fh; print $fh $gd->png; # plot() returns a GD::Image close $fh; ``` `GD::Graph::bars`, `::lines`, `::pie`, and `::points` are the workhorses. `plot` returns a `GD::Image`, so everything from the [GD chapter](raster-gd-magick.md) about output applies. This is the pragmatic default for a chart on disk. ### SVG for vector charts When the chart must stay sharp at any size, or live in a web page as markup, build it as [SVG](vector-cairo-svg.md) directly. There is no chart abstraction to learn: you compute the bar rectangles and axis lines yourself and emit them. That is more code than `GD::Graph`, but it is resolution-independent and needs no compiled dependency. ```perl use SVG; my @values = (12, 19, 8, 23); my $svg = SVG->new(width => 400, height => 300); my $base = 260; # baseline y my $bw = 60; # bar width for my $i (0 .. $#values) { my $h = $values[$i] * 8; # scale to pixels my $x = 40 + $i * ($bw + 20); $svg->rect(x => $x, y => $base - $h, width => $bw, height => $h, style => { fill => 'steelblue' }); } $svg->line(x1 => 30, y1 => $base, x2 => 380, y2 => $base, style => { stroke => 'black' }); print $svg->xmlify; ``` For anything beyond a simple bar or line chart the hand-rolled SVG grows quickly, but for exactly the common cases it is clean and dependency-free. ### The legacy options, named Two charting modules you will find referenced online are effectively unmaintained and are noted here only so their state is not a surprise. **`Chart::Clicker`** produces attractive Cairo-rendered charts but has not seen a release in years and carries a large dependency tree (including Moose); if you already run it, it works, but it is not a choice for new code. **`Chart::Gnuplot`** drives an external `gnuplot` binary and is likewise dormant; if you have `gnuplot` installed and want its plotting power, calling it directly (or through a thin wrapper of your own) is more maintainable than depending on the abandoned module. For scientific plotting specifically, the PDL ecosystem’s own graphics modules are the better-supported path and belong with PDL rather than here. ## Where this leaves the toolkit arc You can now create, load, draw on, filter, save, vectorize, inspect, and chart 2D images entirely on disk. The one thing missing is a **screen**: getting a drawing into a live, interactive window. That is the [next chapter](gui-toolkits.md), and it is also the bridge to the two capstone projects, which both need a window to run in.