Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations SkipVought on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

ID a gif text image and output ascii text? 2

Status
Not open for further replies.

RosinCoreSolder

Technical User
Jul 30, 2006
6
0
0
US
Hello,
I have been placing Solar-X-Ray
status.gif
and Geomagnetic-Field status
kpstatus.gif
reports on my web site from n3kl.org. Each time a visitor accesses my site, these two status images containing words are downloaded from n3kl.org telling the current status, useful in predicting radio propagation.

It is my desire to take these images, identify them and output an ascii text word to my visitor, in the alt tag, which now contains the static output "Status." Doing so would avail this information to blind users whose screen readers do not discern the image text.

With a hex editor, I have determined that the 114th byte of the eight possible GIF images is unique, so I could use a cgi script using Perl, or a php script, on my SSI-enabled Apache web site to perform this conversion. I also run Apache Web server, with Perl and SSI enabled on my Windows machine for local development.

I am still a little green on this Perl, and have searched Google for anything useful without much luck.

I can fairly quickly write a DOS program in QuickBASIC that could open a file on the hard drive and extract the specified byte and match it up, so there must be a way to do this on a server side script using a freshly downloaded image.

Any pointers or resources you could start me on would be appreciated. My thanks in advance!

--
Larry
 
have a look at the seek, or depending on the size of the file you could 'slurp' it and read it as a string

Code:
open FILE, "<whatever.gif";
$/=undef;
$file_contents=<FILE>;
clsoe FILE;
@decisions=split (//,$file_contents);
print $decisions[114];

Not tested BTW ;-)


Paul
------------------------------------
Spend an hour a week on CPAN, helps cure all known programming ailments ;-)
 
...these two status images containing words are downloaded from n3kl.org...

Do you really mean that they're downloaded to your server, or is it actually that you put a reference in your page directly to something like [tt]n3kl.org/images/current_status.gif[/tt], and n3kl make sure that the appropriate image is present at that URL.

If the latter, you'll need to use the LWP module to read the image from their server before digging around in its 114th byte.

Having done all that, I'd suggest outputting the "Normal", "Quiet", whatever status as plain text (styled with some CSS) rather than using their original image with an [tt]alt[/tt] attribute. That will allow people to re-size the text if they need to.

-- Chris Hunt
Webmaster & Tragedian
Extra Connections Ltd
 
Dear ChrisHunt,
I am relatively new to Perl, without a whole lot of developmental from-scratch experience, and have been doing a lot of online reading to reacquaint myself with its workings since I opened this thread. Documentation from and from tips from this site's Perl forum faqs and other places have helped my understanding.

My web host runs Perl 5.8.0 on an Apache Web server on Linux. I am running ActivePerl 5.8.8 on an Apache web server on Windows XP for my local development. I even installed Perl at \usr\bin to match my web site's /usr/bin path.


You are right, I need to emulate a Web browser, and retrrieve the two images from the n3kl web site, store the images on my web site in a temporary area or in memory, and look at the 114th byte and perform like a BASIC Select Case to match like the "Normal" image to the text word "Normal," or the "Active" image to the word "Active," for display to my visitor.

At this point I have a script running that will convert a time display from UTC to my local time zone, and work with scalar variables, and display a Web page containing these active ingredients.

I will concentrate on the lwp module and see if I can get those images down here for processing. When I get something near working order, I will post it.

--
Larry
 
select case isn't an option in perl, at least out of the box, though this module Switch will be useful no doubt

HTH
--Paul

Paul
------------------------------------
Spend an hour a week on CPAN, helps cure all known programming ailments ;-)
 
Hi Guys,
I have a page up and running on now, thanks to Paul's and Chris' suggestions.

I start my code off with
Code:
#!/usr/bin/perl -w
# solar.cgi

# Use strict and use diagnostics 
# create warnings and suggestions 
# in my server error log.
# Also must declare global variables using our().

use strict;
use diagnostics;
our($Xray,$X_img,$Geom,$G_img);

and then I employed the LWP code straight out of the documentation at the top of the page at:

By declaring my globals at the top, that let me move all of my decisionmaking to below the LWP code, and Web page generation in one block below that.

There is one problem that I have, with trying to use a subroutine for Web page creation. I declared one at the top and tried to call it at the bottom, but it was undefined at the time of the call, and after repeated "500" errors, I gave up on that.

I found that when my Internet was offline, the script would generate "500" errors when it could not reach n3kl.org, with always incomplete headers as the first error entry in the log.

My solution to that was to generate a Web page output before I died. And because I ran two passes of LWP to visit and obtain the two images, I needed to enter duplicate code in two places.

I used Paul's seek example code, from after he closed the file, because I held the images in my $response -> content variable. His code worked, and gave me a string character, which I used ord() on to get the byte value.

I tried to use switch and case, but I had an error somewhere, maybe one of those deals where there is some invisible character in there, for I could never find it. Still had same problem when I had if .. elsif, until I simply took one sequence that was working and copied it over the second sequence that was being the show-stopper. Re-entered my variable names and data, and it took right off.

In my following post, I will list my entire program script. I would like any suggestions on how I might implement subroutines to cut down on redundancy, and also have another question.

As it stands now, I have the images in memory, $X_img and $G_img, but I am not utilizing these variables in any way as yet. I would like to display the images in the Web page without having to write them to disk. Of course, I could write them to disk and then use a <img src=> tag to call that file, but if there is a way to not have to do that, it would make for a faster page. It would be nice to add the image along with the text that I have created, without making a second visit to the n3kl.org site to obtain the images again.

I find there to be a lot of nonsense in the documentation for Perl. Like one thing I read, this use is just slightly deprecated, and may eventually be removed from Perl, say around the year 2168. And the evaluation order of things is made very unnecessarily complicated. Something about the right-hand commas being evaluated first in (1,3,sort4,2). It outputs from left to right 1,3,2,4.

I will sometimes find someone making much better sense through some obscure search than I find in the docs, but enough on the soapbox. :)

Thank you for your help, and I appreciate the tips!

Larry
 
[red]As promised,[/red] the working script which identifies
the words on the image text and outputs words in
ascii text:
Code:
#!/usr/bin/perl -w
# solar.cgi
# By Larry Kuck

# Use strict and use diagnostics 
# create warnings and suggestions 
# in my server error log.
# Also must declare global variables using our().

use strict;
use diagnostics;
our($Xray,$X_img,$Geom,$G_img);

# taken straight from the top of 
# [URL unfurl="true"]http://search.cpan.org/~gaas/libwww-perl-5.805/lib/LWP/UserAgent.pm#NAME[/URL]

require LWP::UserAgent; 
my $ua = LWP::UserAgent->new; 
$ua->timeout(10); 
$ua->env_proxy; 

# First Pass
# Obtain Solar Xray status from N3KL.org  

my $response = $ua->get('[URL unfurl="true"]http://www.n3kl.org/sun/images/status.gif?');[/URL] 
if ($response->is_success) {

# Image file is contained in $response -> content.
$X_img=$response -> content;
my @decisions=split (//,$response -> content);
$Xray = (ord $decisions[113]);
}
 else {
print qq
{~Content-Type: text\/html

<!DOCTYPE html 
     PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
     "[URL unfurl="true"]http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">[/URL]

<html>
<head>
<title>
($Xray, $Geom) N3KL Solar Monitor 
</title>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
</head>
<body>
<div style="width:27em; margin:auto;text-align:center;">
<h1>N3KL Solar Monitor</h1>
<p>
Unable to retrieve data from n3kl.org.&nbsp; Please try later.
</p>

</body>
</html>
};

die $response->status_line;
 }

# Second Pass
# Obtain Geomagnetic Field status from N3KL.org

$response = $ua->get('[URL unfurl="true"]http://www.n3kl.org/sun/images/kpstatus.gif?');[/URL] 
if ($response->is_success) {

# Image file is contained in $response -> content.
$G_img=$response -> content;
my @decisions=split (//,$response -> content);
$Geom = (ord $decisions[113]);
 }
 else {
print qq
{~Content-Type: text\/html

<!DOCTYPE html 
     PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
     "[URL unfurl="true"]http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">[/URL]

<html>
<head>
<title>
($Xray, $Geom) N3KL Solar Monitor 
</title>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
</head>
<body>
<div style="width:27em; margin:auto;text-align:center;">
<h1>N3KL Solar Monitor</h1>
<p>
Unable to retrieve data from n3kl.org.&nbsp; Please try later.
</p>

</body>
</html>
};

die $response->status_line;
 }
# End of WLP code

# Match the images to the words:
#  Xray Status:
	if ($Xray==45)		{$Xray="Normal";
}	elsif ($Xray==74)		{$Xray="Active";
}	elsif ($Xray==113)	{$Xray="M Class Flare";
}	elsif ($Xray==147)		{$Xray="X Class Flare";
}	elsif ($Xray==246)	{$Xray="MEGA FLARE!";
}	else	{; #if status no match, just leave $Xray with numeric value
}

# Geomagnetic Field Status:
	if ($Geom==14)		{$Geom="Quiet";
}	elsif ($Geom==86)		{$Geom="Unsettled";
}	elsif ($Geom==31)	{$Geom="Storm";
}	else	{; #if status no match, just leave $Geom with  numeric value
}

#Time to produce a Web page:
print qq
{~Content-Type: text\/html

<!DOCTYPE html 
     PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
     "[URL unfurl="true"]http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">[/URL]

<html>
<head>
<title>
($Xray, $Geom) N3KL Solar Monitor 
</title>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
<meta name="DESCRIPTION" content="This Text-Based solar monitor interface delivers the same information as is delivered by the image-based Solar Monitor from [URL unfurl="true"]www.n3kl.org.[/URL] " />
<meta name="KEYWORDS" content="solar,geomagnetic field, nonitor,n3kl" />
<link rel="stylesheet" href="x.css" type="text/css" media="" />

</head>
<body>

<div class="shell">
<h1>N3KL Solar Monitor</h1>
<div class="status">
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Solar X-Rays:&nbsp;&nbsp;:<a href="[URL unfurl="true"]http://www.n3kl.org/sun/noaa.html"[/URL] title="Status">$Xray</a>:<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Geomagnetic&nbsp;Field:&nbsp;&nbsp;:<a href="[URL unfurl="true"]http://www.n3kl.org/sun/noaa.html"[/URL] title="Status">$Geom</a>:<br />&nbsp;
</div>
<div class="bottomline">
From <a href="[URL unfurl="true"]http://www.n3kl.org/sun/noaa.html">N3KL.org</a>[/URL]
</div>
</div>


<p class="nav">
This page hosted by the <br />
<a href="[URL unfurl="true"]http://wb7tjd.org/">Superstition[/URL] Amateur Radio Club</a> <br />
at wb7tjd.org/status/
</p>
<p class="credit">
This page was generated by <br />
a Perl script written by <br />
Larry Kuck, WB7CRK.&nbsp; <br />
It utilizes information <br />
provided by n3kl.org.<br />
<br />
<i>August 03, 2006</i>
</p>

</body>
</html>
};

Suggestions for improvements, particularly,
how to properly define a subroutine and call it
are appreciated, and I thank the fine folks I
have come across in this forum!


Larry
 
Quick update, to close out this discussion thread with:

Paul, I tried the switch module code again and met with
success this time.

Recall that I tried it and reported:
... but I had an error somewhere, maybe ... some
invisible character in there, for I could never find it.
Still had same problem when I had if .. elsif, until I
simply took one sequence that was working and copied it
over the second sequence that (wasn't working).

Apparently that rewrite cured whatever it was that prevented success with switch the first time.

This functioning code is a direct replacement for the
if..elsif blocks:
Code:
# End of WLP code

# Match the images to the words:

	use Switch;

#  X-Ray Status:
	switch	($Xray)	{

	case 45	{ $Xray="Normal"	}
	case 74	{ $Xray="Active"	}
	case 113{ $Xray="M Class Flare"	}
	case 147{ $Xray="X Class Flare"	}
	case 246{ $Xray="MEGA FLARE!"	}
	else	{ $Xray="$Xray Script Error!" }
	}

# Geomagnetic Field Status:
	switch	($Geom)	{

	case 14	{ $Geom="Quiet"	}
	case 86	{ $Geom="Unsettled"	}
	case 31	{ $Geom="STORM!"	}
	else	{ $Geom="$Geom Script Error!" }
	}

Thank you again for your hints.
Larry
 
I think trying to read and use both images, and display the page they're used on, is rather gonna be fiddly to work with going forward. Here's how I'd do it instead...

Use Server Side Includes (see faq253-3309 and faq253-2000 for info) to incorporate each status symbol where you want it. With most web servers, you will have to give your web page a .shtml extension to trigger any SSI instructions it contains. So your page should be called, say, status.shtml and look something like this:
Code:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
 "[URL unfurl="true"]http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">[/URL]
<html>
<head>
  <title>N3KL Solar Monitor</title>
  <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
  <link rel="stylesheet" href="x.css" type="text/css" media="" />
</head>
<body>
  <div class="shell">
    <h1>N3KL Solar Monitor</h1>
    <div class="status">
       X Ray: <!--#include virtual="/cgi-bin/xray.pl" --><br />
       Geomagnetic: <!--#include virtual="/cgi-bin/magnet.pl" -->
    </div>
    ... etc. ...
  </div>
</body>
</html>
Now you have two scripts to write, each of which requests the relevant image, digs out the appropriate byte and outputs some suitable XHTML. Here's xray.pl (I'm not testing this, so it may have the odd bug):
Code:
#!/usr/bin/perl -w
# adapted from solar.cgi by putting it on a piece of wood
# and banging a few nails through it

# Use strict and use diagnostics
# create warnings and suggestions
# in my server error log.
# Also must declare global variables using our().

use strict;
use diagnostics;
our($Xray,$X_img,$class,$text);

# taken straight from the top of
# [URL unfurl="true"]http://search.cpan.org/~gaas/libwww-perl-5.805/lib/LWP/UserAgent.pm#NAME[/URL]

require LWP::UserAgent;
my $ua = LWP::UserAgent->new;
$ua->timeout(10);
$ua->env_proxy;

# Obtain Solar Xray status from N3KL.org  

my $response = $ua->get('[URL unfurl="true"]http://www.n3kl.org/sun/images/status.gif?');[/URL]
if ($response->is_success) {
   # Image file is contained in $response -> content.
   $X_img=$response -> content;
   my @decisions=split (//,$response -> content);
   $Xray = (ord $decisions[113]);

    if ($Xray==45) {
       $class="x_normal";
       $text="Normal";
    } elsif ($Xray==74){
       $class="x_active";
       $text="Active";
    } elsif ($Xray==113) {
       $class="x_Mclass";
       $text="M Class Flare";
    } elsif ($Xray==147) {
       $class="x_Xclass";
       $text="X Class Flare";
    } elsif ($Xray==246) {
       $class="x_mega";
       $text="MEGA FLARE!";
    } else {
       $class="x_error";
       $text="Unknown - $Xray";
    }
} else {
   $class="x_error";
   $text="Unavailable";
}

# Send a MIME header...
print"Content-Type: text/html\n\n";

# ...and a snippet of HTML
print "<span class=\"$class\">$text</span>\n";
The other script will be similar - I won't bother to write it out. What you end up with is two self-contained scripts which can be plugged into your page where you want them, in much the same way as the original <img> elements were. I think you'll find this easier to maintain.

All you have to do now is add some CSS to your stylesheet to get each status element displayed as you want it.


-- Chris Hunt
Webmaster & Tragedian
Extra Connections Ltd
 
Chris,
Your script ran straight out of the box, and I thank you for the suggestion. What I have done, however, is do away with the web page entirely from the script. I only send a header to the browser before exiting the script. Instead, I am printing the status to the server hard drive and then calling it up in SSI calls.

I am running a modified version of my single script which grabs both images, then uses the switch/case code. And because it appears that while you could run several commands in one if block, the case block only supports one action per case, so I introduced myself to the Perl array.

I our (@xray, @$geom); at the top and then save the X-Ray status in one array field and the class in the other, then do the same with the geomagnetic status and class.

I am sending out two files to disk for each status, one just containing the status in plain text and the other containing the html span class snippet surrounding the status.

This lets me display the current status in the page title with plain text.

My next project on this solar monitor page is somehow to have the script check if it has run within the last eight or nine minutes, then if not, go out and check for new updates. The data on n3kl.org is updated every ten minutes. If I can have the script run this check, then I can let it run on many pages of the site without being a bandwidth hog on n3kl resources.

I've really come a fair way from the state of confusion I was starting in, and you and Paul deserve those stars for pointing me up the right way. Thank you!

Larry
 
I can fairly quickly write a DOS program in QuickBASIC that could open a file on the hard drive and extract the specified byte and match it up, so there must be a way to do this on a server side script using a freshly downloaded image."

That's good, i'm not the only one who uses Qbasic then :)
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top