Create CSS Image Sprites
Post ReplyCreate CSS Image SpritesPosted: Monday, May 31, 2021 [22:43:12] - 1
CSS Image Sprites can lower a load on a webserver by reducing number of server requests and in many cases reducing image file size. There are a number of free tools available more or less automated to get sprites coordinates. Combining images is quite a simple task for Gimp or Photoshop software. Many online sites offer combined task of combining images and generating CSS. Very few of them are good or good enough to produce straight-forward code and optimized images at the same time. Here is the Perl program that does it quite well by properly optimizing jpeg/tiff images and producing compact CSS code. It requires ImageMagick and cwebp installed. use strict; use warnings; # This software is free under AL/GPL, copyright (c) 2021 CodeMacs.com # You can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. # Use it at your own risk! # Prerequisites # ImageMagick, cwebp my $dircur='/Web_Folder'; # Web folder for this program my $dirtmp='/Temp_writable_folder'; # Using cgi-lib.pl to process form input our %in=(); if(-f "$dircur/cgi-lib.pl") { unless($@) {&ReadParse;} } unless($in{do}) {default();} ## Print default page is no input my $returnsp='<a href="sprite.cgi">Back to Sprites</a> · '; if($in{do} eq 'upload') {delete $in{do}; sub default { my $sfiles=''; my @fls = `find $dircur/test -name "*.cgi" -print`; # List already built Stripes foreach my $f (@fls) { $f =~ s/\n|\r//g; $fn =~ s/\.\w{3}$//; $sfiles .= "<a href=\"$f\" target=\"_blank\">$fn</a>\n";} if($sfiles) {chomp $sfiles; $sfiles = "\n<p>Already done Sprites:<br />$sfiles</p>";} my $title='Create Sprite images and CSS'; my $htm = "<form method=\"post\" action=\"sprite.cgi\" enctype=\"multipart/form-data\"> <p><b>Images</b></p><p><span id=\"filelist\" class=\"listit\" style=\"display:none\"></span> <span id=\"images\" class=\"cl\"><input type=\"file\" id=\"file1\" name=\"file1\" onchange=\"addfile('1');return false;\"></span> </p> <p>Force JPEG: <input type=\"checkbox\" name=\"force\" value=\"1\"></p> <p>Sprite Name: <input type=\"text\" name=\"sprname\" value=\"$in{sprname}\" class=\"smallfld\"></p> <p><input type=\"submit\" value=\"Create Sprite\" class=\"bgreen\"></p>$sfiles <input type=\"hidden\" name=\"do\" value=\"upload\"></form>"; my $code = "\n<script>function addfile(nmb) { var nxt = +nmb + 1; var idthis = 'file' + nmb; document.getElementById(\"filelist\").style.display = \"inline\"; var file = document.getElementById(idthis).value; var parts = file.split(\"\\\\\"); var fileName = parts[parts.length - 1]; var dlist = document.createElement(\"lst\"); dlist.innerHTML=fileName; document.getElementById(\"filelist\").appendChild(dlist); var crst = document.getElementById(idthis).style; crst.position = \"absolute\"; crst.display = \"inline\"; crst.left = \"-1900px\"; var continc = document.getElementById(\"images\"); var tag = document.createElement(\"span\"); tag.innerHTML = '<input type=\"file\" id=\"file' + nxt + '\" name=\"file' + nxt + '\" onchange=\"addfile(\\'' + nxt + '\\');return false;\">'; continc.appendChild(tag); }\n</script>"; pageprint($title,$htm,$code); } ## END DEFAULT SUB sub pageprint { my($title,$html,$code) = @_; print "Content-type: text/html\n\n"; print "<!doctype html> <html> <head> <meta charset=\"utf-8\"> <title>$title</title> <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"> <link rel=\"stylesheet\" href=\"page.css\" media=\"screen\">$code </head> <body> <div class=\"content\"> <div class=\"header\"><h1>$title</h1></div> <div class=\"main\">$html</div> <div class=\"centlinks\">$returnsp<a href=\"/tools/\">Back to Tools</a></div> </div><!-- Content --> <div class=\"cl\"></div> <div class=\"footer\"><copy>Copyright © 1995 - $ye</copy>This is private services.</div> </body> </html>"; exit(0); } ## END PRINT sub doupload {my $torun=''; $in{sprname} =~ s/\W//g; unless($in{sprname}) {$in{sprname} = 'sprite'.$ENV{REMOTE_USER};} my $nof=0; while(1) {$nof++; if($in{"file$nof"}) { if($inct{"file$nof"} =~ /image/i) {my $filename=''; if($incfn{"file$nof"}) {$filename=$incfn{"file$nof"};} else {$filename = "$nod.tmp";} unless($filename =~ /[[:alpha:]]/) {$filename = "image$nod";} open(IMG,">$dirtmp/$filename"); } ## END IMAGE } ## END IF FILE PRESENT my $diff = $nof - $nod; if($diff > 3) {last;} } ## WHILE END my $nopng=''; if($in{force}) {$nopng=1;} foreach my $im (@files) { my $rests = `identify -format "%wx%h" "$dirtmp/$im"`; unless($w && $h) {next;} my $size = (stat ("$dirtmp/$im"))[7]; my $imtp = `exiftool "$dirtmp/$im" | grep "MIME"`; my $fname=$im; $process{$im}{w}=$w; if($maxh < $h) {$maxh=$h;} if($imtp =~ /png$/i) { `convert -density 72 "$dirtmp/$im" -background white -quality 90 -flatten -colorspace RGB +repage "$dirtmp/$tout"`; } ## END PNG else {$nopng=1; `convert -density 72 "$dirtmp/$im" -quality 90 -flatten -colorspace RGB +repage "$dirtmp/$tout"`; } ## END OTHER FORMAT $next.= "$im\n"; } ## FOREACH FILE END unless(-d "$dircur/test") {$torun .= "mkdir -p $dircur/test\n";} chomp $next; my $pngrun=''; my $posx=0; foreach my $im (@frun) { $pngrun .= " $dirtmp/$im -geometry +$posx+0 -composite"; $jpgrun .= " $dirtmp/$process{$im}{out} -geometry +$posx+0 -composite"; unless($posx == 0) {$pxx='px'; unless($posy == 0) {$pxy='px'; $cmbspr .= "\.$process{$im}{name}, "; $sprite .= "\.$process{$im}{name} {\nwidth:$process{$im}{w}px\;\nheight:$process{$im}{h}px\;\nbackground-position:$mx$posx$pxx $my$posy$pxy;\n}\n"; $thtm .= "<div class=\"$process{$im}{name} thumbp\"></div>\n"; $posx += ($process{$im}{w} + 2); } ## FOREACH IMAGE END my $totinprint=$totin; $printstat .= "Total images size: $totinprint Kb\n"; $cmbspr =~ s/\W+$//; if($nopng) {my $savingjpg=''; `convert -size $posx$x$maxh xc:white -fill white $dirtmp/bkg.$in{sprname}.1.jpg`; `convert -density 72 $dirtmp/bkg.$in{sprname}.1.jpg $dirtmp/bkg.$in{sprname}.jpg`; `convert -density 72 $dirtmp/bkg.$in{sprname}.jpg$jpgrun -quality 55 -flatten -colorspace RGB +repage $dirtmp/$in{sprname}.jpg`; my $size = (stat ("$dirtmp/$in{sprname}.jpg"))[7]; if($size < $totin) {$savingjpg = $totin - $size; $savingjpg = " saved $savingjpg Kb";} else {$savingjpg = $size - $totin; $savingjpg = " lost $savingjpg Kb";} $size /= 1024; $cmbspr = "$cmbspr {background:url(\"$in{sprname}.jpg\");}\n"; `cwebp -q 50 $dirtmp/$in{sprname}.jpg -o $dirtmp/$in{sprname}.webp`; my $sizew = (stat ("$dirtmp/$in{sprname}.webp"))[7]; if($sizew < $totin) {$savingwbp = $totin - $sizew; $savingwbp = " saved $savingwbp Kb";} else {$savingwbp = $sizew - $totin; $savingwbp = " lost $savingwbp Kb";} $sizew /= 1024; $printstat .= "\nSprites:\n$in{sprname}.jpg $size Kb$savingjpg\n$in{sprname}.webp $sizew Kb$savingwbp\n"; $torun .= "cp $dirtmp/$in{sprname}.jpg $dircur/test/$in{sprname}.jpg\n"; $torun .= "cp $dirtmp/$in{sprname}.webp $dircur/test/$in{sprname}.webp\n"; } ## END JPEG else {my $savingpng=''; `convert -size $posx$x$maxh xc:none -fill white $dirtmp/bkg.$in{sprname}.1.png`; `convert -density 72 $dirtmp/bkg.$in{sprname}.1.png $dirtmp/bkg.$in{sprname}.png`; `convert -density 72 $dirtmp/bkg.$in{sprname}.png$pngrun $dirtmp/$in{sprname}.png`; my $size = (stat ("$dirtmp/$in{sprname}.png"))[7]; if($size < $totin) {$savingpng = $totin - $size; $savingpng = " saved $savingpng Kb";} else {$savingpng = $size - $totin; $savingpng = " lost $savingpng Kb";} $size /= 1024; $cmbspr = "$cmbspr {background:url(\"$in{sprname}.png\");}\n"; $printstat .= "\nSprites:\n$in{sprname}.png $size Kb$savingpng\n"; $torun .= "cp $dirtmp/$in{sprname}.png $dircur/test/$in{sprname}.png\n"; } ## END PNG $thtm = "<p>This is how sprite will render:<br />\n$thtm</p>"; $sprite = "$cmbspr$sprite"; my $src = getsource(); $src =~ s#!STYLE!#\n<style>$sprite</style>#g; $src =~ s#!HTML!#$thtm#g; open(HTM,">$dirtmp/$in{sprname}.cgi"); $torun .= "cp $dirtmp/$in{sprname}.cgi $dircur/test/$in{sprname}.cgi\n"; $torun .= "chown webuser:webgroup $dircur/test/$in{sprname}.cgi\nchmod 711 $dircur/test/$in{sprname}.cgi\n"; # This is optional as we run an old server and it has no access to the program # directory and files have to be moved by a running daemon with higher privileges open(TXT,">>/runitall.txt"); chomp $printstat; my $t='Sprite "'.$in{sprname}.'" created'; my $h = "<p>Sprite image and CSS created.</p> <p>Sprite:<br />\n$sprite</p> <p>Image statistics:<br />\n$printstat</p> <p><a href=\"test/$in{sprname}.cgi\" target=\"_blank\">See it in action</a>."; pageprint($t,$h,''); } ## END SUB DO UPLOAD sub getsource { my $src = '#!/opt/local/bin/perl use strict; use warnings; my $tmnow = time; my $html = \'!HTML!\'; my $style=\'!STYLE!\'; if($ENV{HTTP_ACCEPT} =~ /image\/webp/) {$html =~ s#\.jpg"#\.webp"#i; print "Content-type: text/html\n\n"; print <<EOH; <!doctype html> <html> <head> <meta charset="utf-8"> <title>Sprite Test !TITLE!</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="../page.css" media="screen">$style </head> <body> <div class="content"> <div class="header"><h1>Sprite test !TITLE!</h1></div> <div class="main">$html</div> <div class="centlinks"><a href="/tools/">Back to Tools</a></div> </div><!-- Content --> <div class="cl"></div> <div class="footer"><copy>Copyright © 1995 - $ye</copy>This is private services.</div> </body> </html> EOH exit(0);'; return $src; } ## END GET SOURCE Next - CSS file for complete program. |
RE: Create CSS Image SpritesPosted: Monday, May 31, 2021 [22:48:11] - 2
This is a CSS file for the program. Unfortunately, input[type="file"]:before is not properly works in latest Safari for Mac but since this program designed for IntraNet it shouldn't be a big issue. font-family: 'Open Sans'; font-style: normal; font-weight: 300; src: local('Open Sans Light'), local('OpenSans-Light'), url(/fonts/OpenSans-Light.woff2) format('woff2'); unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; } @font-face { font-family: 'Open Sans'; font-style: normal; font-weight: 300; src: local('Open Sans Light'), local('OpenSans-Light'), url(/fonts/OpenSans-Light2.woff2) format('woff2'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } @font-face { font-family: 'Open Sans'; font-style: bold; font-weight: 600; src: local('Open Sans SemiBold'), local('OpenSans-SemiBold'), url(/fonts/OpenSans-SemiBold.r.woff2) format('woff2'); unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; } @font-face { font-family: 'Open Sans'; font-style: bold; font-weight: 600; src: local('Open Sans SemiBold'), local('OpenSans-SemiBold'), url(/fonts/OpenSans-SemiBold.e.woff2) format('woff2'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } /*,sans-serif,"Helvetica Neue",Helvetica,Arial*/ body { font-family: "Open Sans"; -ms-text-size-adjust: 100%; -webkit-text-size-adjust: 100%; font-size: 1.2em; line-height: 1.25; margin: 1em; } a { text-decoration: none; color: #528aff; } a:hover { text-decoration: underline; color: #0432ff; } a:visited { color: #76a2c4; } #content { width: 90vw; margin-right: auto; margin-left: auto; border: 1px solid rgba(66,66,66,0.7); -webkit-border-radius: 5px; -moz-border-radius: 5px; border-radius: 5px; background-color: #f2f2f2; padding: 1em; -webkit-box-shadow: 0px 2px 5px 1px rgba(0,0,0,0.47); -moz-box-shadow: 0px 2px 5px 1px rgba(0,0,0,0.47); box-shadow: 0px 2px 5px 1px rgba(0,0,0,0.47); } h3 { margin-top: 0; } p { margin-bottom: 0; } b, strong { font-weight: bold; font-size: 101%; } .content { display: block; margin-bottom: 1em; margin-top: 1em; } .header { min-height: 2em; display: block; border-bottom: 1px solid #86a5d5; } .header h1 { color: #1e9dff; font-size: 1.5em; } .cl { display: block; clear: both; } .footer { font-size: 0.9em; border-top: 1px solid #e1e1e1; padding-top: 0.4em; } .footer copy { float: right; font-size: 0.75em; } .listit { float: right; max-width: 65%; display: inline; text-align: right; font-size: 85%; width: auto; margin-bottom: 0.5em; border: 1px solid #88c0a7; padding: 10px; -webkit-border-radius: 5px; -moz-border-radius: 5px; border-radius: 5px; } .listit lst { display: block; } input[type="file"] { height: 35px; outline: none; } input[type="file"]:before { content: "Choose File"; background: #fff; width: 12em; height: 35px; display: block; text-align: center; position: relative; left: -6px; border: 1px solid #9e9e9f; top: 2px; line-height: 35px; color: #c22c18; display: block; font-weight: bold; -webkit-border-radius: 5px; -moz-border-radius: 5px; border-radius: 5px; font-size: 1.5em; margin: 0 5px; clear: right; visibility: visible; z-index: 999; } input[type=submit] { background-color: #aaadb2; color: white; padding: 8px 16px; text-decoration: none; margin: 4px 2px; cursor: pointer; -webkit-border-radius: 8px; -moz-border-radius: 8px; border-radius: 8px; font-size: 1.15em; border: 1px solid #ebeaec; box-shadow: 3px 3px 4px rgba(0, 0, 0, 0.2); -webkit-box-shadow: 3px 3px 4px rgba(0, 0, 0, 0.2); -moz-box-shadow: 3px 3px 4px rgba(0, 0, 0, 0.2); } input[type=submit]:hover { box-shadow: 3px 3px 4px rgba(0, 0, 0, 0); -webkit-box-shadow: 3px 3px 4px rgba(0, 0, 0, 0); -moz-box-shadow: 3px 3px 4px rgba(0, 0, 0, 0); } .bgreen { background-color: #4CAF50!important; } .bblue { background-color: #008CBA!important; } /* Blue */ .bred { background-color: #f44336!important; } /* Red */ .bblack { background-color: #555555!important; color: #feffff!important; } /* Black */ .bgrey { background-color: #e7e7e7!important; color: black!important; } /* Gray */ .centlinks { text-align: center; font-size: 90%; margin-top: 1em; margin-bottom: 1em; } input[type=text] { padding: 3px 5px; margin: 8px 0; box-sizing: border-box; font-size: 0.9em; } .smallfld { width: 8vw; } .thumbp { margin-right: 15px; margin-bottom: 15px; display: inline-block; vertical-align: top; /* -webkit-box-shadow: 3px 3px 7px 0px rgba(0,0,0,0.38); -moz-box-shadow: 3px 3px 7px 0px rgba(0,0,0,0.38); box-shadow: 3px 3px 7px 0px rgba(0,0,0,0.38); */ } .thumbp:hover { -webkit-box-shadow: 1px 1px 7px 0px rgba(0,0,0,0.38); -moz-box-shadow: 1px 1px 7px 0px rgba(0,0,0,0.38); box-shadow: 1px 1px 7px 0px rgba(0,0,0,0.38) } Please let us know if other issues encountered |
RE: Create CSS Image SpritesPosted: Monday, May 31, 2021 [23:40:35] - 3
Program screenshots: CSS created: .reload {width:125px;height:123px;background-position:0 0;} .spray {width:124px;height:126px;background-position:-127px 0;} .bubbles {width:128px;height:126px;background-position:-253px 0;} .home {width:128px;height:126px;background-position:-383px 0;} .handwash {width:131px;height:128px;background-position:-513px 0;}</style> fast and simple |