This is one of the most interesting questions I've seen! I agree with some other posts that rendering a bitmap and then analyzing the bitmap would be the most reliable solution. For simple PDFs, a faster but less complete approach is here.
- Parsing each PDF page
- Look for color directives (g, rg, k, sc, scn, etc.)
- Look at the embedded images, analyze the color
My solution is below # 1 and half # 2. The other half of No. 2 will follow the user-defined color, which includes searching for entries / ColorSpace on the page and decoding them - contact me offline if you are interested, as it is very convenient but not in 5 minutes.
First, the main program:
use CAM::PDF; my $infile = shift; my $pdf = CAM::PDF->new($infile); PAGE: for my $p (1 .. $pdf->numPages) { my $tree = $pdf->getPageContentTree($p); if (!$tree) { print "Failed to parse page $p\n"; next PAGE; } my $colors = $tree->traverse('My::Renderer::FindColors')->{colors}; my $uncertain = 0; for my $color (@{$colors}) { my ($name, @rest) = @{$color}; if ($name eq 'g') { } elsif ($name eq 'rgb') { my ($r, $g, $b) = @rest; if ($r != $g || $r != $b) { print "Page $p is color\n"; next PAGE; } } elsif ($name eq 'cmyk') { my ($c, $m, $y, $k) = @rest; if ($c != 0 || $m != 0 || $y != 0) { print "Page $p is color\n"; next PAGE; } } else { $uncertain = $name; } } if ($uncertain) { print "Page $p has user-defined color ($uncertain), needs more investigation\n"; } else { print "Page $p is grayscale\n"; } }
And then here is a helper renderer that handles the color directives on each page:
package My::Renderer::FindColors; sub new { my $pkg = shift; return bless { colors => [] }, $pkg; } sub clone { my $self = shift; my $pkg = ref $self; return bless { colors => $self->{colors}, cs => $self->{cs}, CS => $self->{CS} }, $pkg; } sub rg { my ($self, $r, $g, $b) = @_; push @{$self->{colors}}, ['rgb', $r, $g, $b]; } sub g { my ($self, $gray) = @_; push @{$self->{colors}}, ['rgb', $gray, $gray, $gray]; } sub k { my ($self, $c, $m, $y, $k) = @_; push @{$self->{colors}}, ['cmyk', $c, $m, $y, $k]; } sub cs { my ($self, $name) = @_; $self->{cs} = $name; } sub cs { my ($self, $name) = @_; $self->{CS} = $name; } sub _sc { my ($self, $cs, @rest) = @_; return if !$cs;