############################################################################## # # Jarl - XPM Code # Perl code to handle manipulating XPM images. Overlaying and merging them # for whiteboard and icon usage. # ############################################################################## ############################################################################## # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # Jabber # Copyright (C) 1998-1999 The Jabber Team http://jabber.org/ # ############################################################################## ############################################################################## # # jarlXPM_Parse - read in an XPM file and build a hash that other XPM # functions can parse. # ############################################################################## sub jarlXPM_Parse { my $file = shift; my %colors; my %symbols; my @xpm; my @xpmData = split("\n", &jarlXPM_Cache($file)); shift(@xpmData); shift(@xpmData); $_ = shift(@xpmData); my ($width,$height,$numcolors,$pixelwidth) = /^\"(\d+) (\d+) (\d+) (\d+)\",$/; foreach (1..$numcolors) { $_ = shift(@xpmData); my ($symbol,$rgb) = /^\"(.{$pixelwidth})\s+c\s+(\S+)\",/; $colors{$rgb} = $symbol; $symbols{$symbol} = $rgb; } foreach my $index (0..($height-1)) { $xpm[$index] = ""; $_ = shift(@xpmData); my ($data) = /^\"(.+)\"/; $xpm[$index] = $data; } return ( height=>$height, width=>$width, pixelwidth=>$pixelwidth, colors=>\%colors, symbols=>\%symbols, xpm=>\@xpm ); } ############################################################################## # # jarlXPM_Merge - takes a list of paths to files, uses the first as a base # image, and overlays the rest of the files on top of it in # that order. It returns a new XPM in string format. # ############################################################################## sub jarlXPM_Merge { my ($baseFile,@overlayFiles) = @_; my %baseXPM = &jarlXPM_Parse($baseFile); foreach my $overlayFile (@overlayFiles) { my %overlayXPM = &jarlXPM_Parse($overlayFile); %baseXPM = &jarlXPM_Overlay(\%baseXPM,\%overlayXPM); } return &jarlXPM_Create(%baseXPM); } ############################################################################## # # jarlXPM_Overlay - take a base image, an overlay image, and an offset of # where to overlay the overlay xpm. # ############################################################################## sub jarlXPM_Overlay { my $baseXPM = shift; my $overlayXPM = shift; my $startX = shift; my $startY = shift; $startX = 0 unless defined($startX); $startY = 0 unless defined($startY); my %baseXPM = %{$baseXPM}; my %overlayXPM = %{$overlayXPM}; my %symbolMap; if ($overlayXPM{pixelwidth} != $baseXPM{pixelwidth}) { if ($overlayXPM{pixelwidth} < $baseXPM{pixelwidth}) { foreach my $symbol (keys(%{$overlayXPM{symbols}})) { my $newsymbol = $symbol."z"x($baseXPM{pixelwidth}-$overlayXPM{pixelwidth}); $overlayXPM{symbols}->{$newsymbol} = $overlayXPM{symbols}->{$symbol}; $overlayXPM{colors}->{$overlayXPM{symbols}->{$symbol}} = $newsymbol; delete($overlayXPM{symbols}->{$symbol}); } foreach my $row (0..$#{$overlayXPM{xpm}}) { $overlayXPM{xpm}->[$row] = join("z"x($baseXPM{pixelwidth}-$overlayXPM{pixelwidth}),grep { $_ ne ""; } split(/(.{$overlayXPM{pixelwidth}})/,$overlayXPM{xpm}->[$row]))."z"; } $overlayXPM{pixelwidth} = $baseXPM{pixelwidth}; } else { foreach my $symbol (keys(%{$baseXPM{symbols}})) { my $newsymbol = $symbol."z"x($baseXPM{pixelwidth}-$baseXPM{pixelwidth}); $baseXPM{symbols}->{$newsymbol} = $baseXPM{symbols}->{$symbol}; $baseXPM{colors}->{$baseXPM{symbols}->{$symbol}} = $newsymbol; delete($baseXPM{symbols}->{$symbol}); } foreach my $row (0..$#{$baseXPM{xpm}}) { $baseXPM{xpm}->[$row] = join("z"x($baseXPM{pixelwidth}-$baseXPM{pixelwidth}),grep { $_ ne ""; } split(/(.{$baseXPM{pixelwidth}})/,$baseXPM{xpm}->[$row])); } $baseXPM{pixelwidth} = $overlayXPM{pixelwidth}; } } foreach my $color (keys(%{$overlayXPM{colors}})) { if (exists($baseXPM{colors}->{$color})) { $symbolMap{$overlayXPM{colors}->{$color}} = $baseXPM{colors}->{$color}; $overlayXPM{colors}->{$color} = $baseXPM{colors}->{$color}; $overlayXPM{symbols}->{$overlayXPM{colors}->{$color}} = $color; } else { my @symbolList = ("a".."z"); push(@symbolList,"A".."Z"); foreach my $symbol (@symbolList) { my $newsymbol = $symbol."z"x($baseXPM{pixelwidth}-1); if (!exists($baseXPM{symbols}->{$newsymbol}) && !exists($overlayXPM{symbols}->{$newsymbol})) { $symbolMap{$overlayXPM{colors}->{$color}} = $newsymbol; $overlayXPM{colors}->{$color} = $newsymbol; $overlayXPM{symbols}->{$newsymbol} = $color; last; } } } } foreach my $y (0..$#{$overlayXPM{xpm}}) { next if (($y+$startY) > $#{$baseXPM{xpm}}); my $uncompressedBase = $baseXPM{xpm}[$y+$startY]; my $compressedData = $overlayXPM{xpm}[$y]; my $overlayIndex = $startX; while($compressedData ne "") { my $char = substr($compressedData,0,$overlayXPM{pixelwidth}); $char = $symbolMap{$char}; if ($overlayXPM{symbols}->{$char} ne "None") { if ($overlayXPM{symbols}->{$char} ne "") { substr($uncompressedBase,$overlayIndex,$baseXPM{pixelwidth}) = $char; } else { substr($uncompressedBase,$overlayIndex,$baseXPM{pixelwidth}) = $overlayXPM{colors}->{'None'}; } } $overlayIndex += $baseXPM{pixelwidth}; substr($compressedData,0,$overlayXPM{pixelwidth},""); $baseXPM{symbols}->{$char} = $overlayXPM{symbols}->{$char} if !exists($baseXPM{symbols}->{$char}); } $baseXPM{xpm}[$y+$startY] = $uncompressedBase; } foreach my $symbol (keys(%{$baseXPM{symbols}})) { $baseXPM{colors}->{$baseXPM{symbols}->{$symbol}} = $symbol; } return %baseXPM; } ############################################################################## # # jarlXPM_Create - takes an XPM hash and builds the string for the file. # ############################################################################## sub jarlXPM_Create { my (%baseXPM) = @_; my $xpm = "/* XPM */\n"; $xpm .= "static char * xpm[] = {\n"; $xpm .= "\"$baseXPM{width} $baseXPM{height} ".scalar(keys(%{$baseXPM{colors}}))." $baseXPM{pixelwidth}\",\n"; foreach my $color (keys(%{$baseXPM{colors}})) { $xpm .= "\"$baseXPM{colors}->{$color} c $color\",\n"; } foreach my $y (0..$#{$baseXPM{xpm}}) { $xpm .= "\""; $xpm .= $baseXPM{xpm}[$y]; $xpm .= "\"\,\n"; } $xpm =~ s/\,\n$//; $xpm .= "\}\;\n"; return $xpm; } ############################################################################## # # jarlXPM_Cache - goes to the cache for the xpm data, reads it in if it is not # in the cache, and returns the xpm file in a string. # ############################################################################## sub jarlXPM_Cache { my $filename = shift; # if (!exists($xpmcache{$filename})) { open(XPM,$filename); my @xpm = ; close(XPM); # $xpmcache{$filename} = join("",@xpm); # } # return $xpmcache{$filename}; return join("",@xpm); } 1;