Saturday, July 31, 2010

A SQL Anywhere Web Service for Displaying Images

Most SQL Anywhere web services are devoted to returning HTML, XML and other text to the client, but they work just fine for binary data too... like images.

Code first, explanation later...


Here's a web service that returns an image to the browser; all it has to do is set the "Content-Type" and return the image as a single-row single-column result set:

CREATE SERVICE rroad_display_image TYPE 'RAW'
AUTHORIZATION OFF USER DBA_image
AS CALL rroad_display_image ( :f );

CREATE PROCEDURE rroad_display_image (
IN @p_file_name VARCHAR ( 100 ) )
BEGIN

CALL dbo.sa_set_http_header( 'Content-Type', 'image/gif' );

SELECT file_image
FROM rroad_image
WHERE file_name = @p_file_name;

END; -- rroad_display_image

In this case, the images are stored in a table, inside the same database where the code for the web service runs:

CREATE TABLE rroad_image (
file_name VARCHAR ( 100 ) NOT NULL,
file_image LONG BINARY NOT NULL,
PRIMARY KEY ( file_name ) );

INSERT rroad_image VALUES ( 'help.gif', dbo.xp_read_file ( 'images\\help.gif' ) );
INSERT rroad_image VALUES ( 'favicon_m.ico', dbo.xp_read_file ( 'images\\favicon_m.ico' ) );

Here's a snippet of code from a "calling" web service called rroad_history_menu that needs to display an image named "help.gif". The <IMG SRC="rroad_display_image?f=help.gif"... tag passes the file name help.gif to the rroad_display_image web service via the parameter named f. When the web page created by rroad_history_menu hits the browser, that IMG tag is evaluated and the rroad_display_image web service is called to return the image:

CREATE SERVICE rroad_history_menu TYPE 'RAW'
AUTHORIZATION OFF USER DBA_history_menu
AS CALL rroad_history_menu ( :z1, -- session id1
:zi, -- sampling id
:sn ); -- sample set number

CREATE PROCEDURE rroad_history_menu (
IN @z1 LONG VARCHAR DEFAULT NULL, -- session id1
IN @zi LONG VARCHAR DEFAULT NULL, -- sampling id
IN @sn LONG VARCHAR DEFAULT NULL ) -- sample set number
RESULT ( html_output LONG VARCHAR )
BEGIN

SELECT STRING (
'<HTML>',

...

--------------------------------------------------
-- Menu: Line 1: Help icon and link

'<A HREF="rroad_help_frame?f=foxhound_history#menu" ',
'TARGET="help_frame" TITLE="Show a description of this menu area in the Help frame">',
'<IMG SRC="rroad_display_image?f=help.gif" BORDER="0" WIDTH="16" HEIGHT="16" HSPACE="0" VSPACE="0" ',
'STYLE="vertical-align: text-bottom; border-bottom: 1px solid blue"> Help</A>    ',

...

'</HTML>' );

END; -- rroad_history_menu

There are several copies of help.gif displayed by rroad_history_menu, one for each context-sensitive Help area; look for the little blue "?" marks:



Here's another snippet of code that needs to return a "favicon" to the browser. When the web page created by the SELECT statement hits the browser, the <LINK ... HREF="rroad_display_image?f=favicon_m.ico" tag tells the browser to turn around and call rroad_display_image to get favicon_m.ico:

CALL dbo.sa_set_http_header( 'Content-Type', 'text/html' );

SELECT STRING (
'<HTML>',
'<HEAD>',
...
'<LINK REL="SHORTCUT ICON" HREF="rroad_display_image?f=favicon_m.ico" />',
'</HEAD>',
...
'</HTML>' );

Here's what favicon_m.ico looks like on the Firefox tab bar (look for the "M"):



The observant reader will notice that it doesn't seem to matter that 'Content-Type' is set to 'image/gif' in the first snippet of code... it works fine for *.ico files, and *.jpg too. Web browsers are wonderfully robust, they really don't mind if your HTML is a bit shaky... even if you commit heresies like forgetting to code the <BODY> tag. It's a good thing HTML came along before XML and all those Politically Correct Programmers who insist <P> without </P> is a crime against humanity, otherwise nobody would get any work done :)

No comments: