1 /*
2     IIP Zoomify Request Command Handler Class Member Function
3 
4     * Development carried out thanks to R&D grant DC08P02OUK006 - Old Maps Online *
5     * (www.oldmapsonline.org) from Ministry of Culture of the Czech Republic      *
6 
7 
8     Copyright (C) 2008-2015 Ruven Pillay.
9 
10     This program is free software; you can redistribute it and/or modify
11     it under the terms of the GNU General Public License as published by
12     the Free Software Foundation; either version 3 of the License, or
13     (at your option) any later version.
14 
15     This program is distributed in the hope that it will be useful,
16     but WITHOUT ANY WARRANTY; without even the implied warranty of
17     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18     GNU General Public License for more details.
19 
20     You should have received a copy of the GNU General Public License
21     along with this program; if not, write to the Free Software Foundation,
22     Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
23 */
24 
25 #include <cmath>
26 
27 #include "Task.h"
28 #include "Transforms.h"
29 #include "Tokenizer.h"
30 
31 
32 
33 using namespace std;
34 
35 
36 
run(Session * session,const std::string & argument)37 void Zoomify::run( Session* session, const std::string& argument ){
38 
39   if( session->loglevel >= 3 ) (*session->logfile) << "Zoomify handler reached" << endl;
40 
41   // Time this command
42   if( session->loglevel >= 2 ) command_timer.start();
43 
44 
45   // The argument is in the form Zoomify=TileGroup0/r-x-y.jpg where r is the resolution
46   // number and x and y are the tile coordinates starting from the bottom left.
47   string prefix, suffix;
48   suffix = argument.substr( argument.find_last_of( "/" )+1, argument.length() );
49 
50   // We need to extract the image path, which is not always the same
51   if( suffix == "ImageProperties.xml" )
52     prefix = argument.substr( 0, argument.find_last_of( "/" ) );
53   else
54     prefix = argument.substr( 0, argument.find( "TileGroup" )-1 );
55 
56 
57   // As we don't have an independent FIF request, we need to run it now
58   FIF fif;
59   fif.run( session, prefix );
60 
61 
62   // Get the full image size and the total number of resolutions available
63   unsigned int width = (*session->image)->getImageWidth();
64   unsigned int height = (*session->image)->getImageHeight();
65 
66 
67   unsigned int tw = (*session->image)->getTileWidth();
68   unsigned int numResolutions = (*session->image)->getNumResolutions();
69 
70 
71   // Zoomify does not accept arbitrary numbers of resolutions. The lowest
72   // level must be the largest size that can fit within a single tile, so
73   // we must discard any smaller than this
74   unsigned int n;
75 
76   unsigned int discard = 0;
77 
78   for( n=0; n<numResolutions; n++ ){
79     if( (*session->image)->image_widths[n] < tw && (*session->image)->image_heights[n] < tw ){
80       discard++;
81     }
82   }
83 
84 
85   if( discard > 0 ) discard -= 1;
86 
87   if( session->loglevel >= 2 ){
88     if( discard > 0 ){
89       *(session->logfile) << "Zoomify :: Discarding " << discard << " resolutions that are too small for Zoomify" << endl;
90     }
91   }
92 
93   // Zoomify clients have 2 phases, the initialization phase where they request
94   // an XML file containing image data and the tile requests themselves.
95   // These 2 phases are handled separately
96   if( suffix == "ImageProperties.xml" ){
97 
98     if( session->loglevel >= 2 ){
99       *(session->logfile) << "Zoomify :: ImageProperties.xml request" << endl;
100       *(session->logfile) << "Zoomify :: Total resolutions: " << numResolutions << ", image width: " << width
101 			  << ", image height: " << height << endl;
102     }
103 
104     int ntiles = (int) ceil( (double)width/tw ) * (int) ceil( (double)height/tw );
105 
106     char str[1024];
107     snprintf( str, 1024,
108 	      "Server: iipsrv/%s\r\n"
109 	      "Content-Type: application/xml\r\n"
110 	      "Last-Modified: %s\r\n"
111 	      "%s\r\n"
112 	      "\r\n"
113 	      "<IMAGE_PROPERTIES WIDTH=\"%d\" HEIGHT=\"%d\" NUMTILES=\"%d\" NUMIMAGES=\"1\" VERSION=\"1.8\" TILESIZE=\"%d\" />",
114 	      VERSION, (*session->image)->getTimestamp().c_str(), session->response->getCacheControl().c_str(), width, height, ntiles, tw );
115 
116     session->out->printf( (const char*) str );
117     session->response->setImageSent();
118 
119     return;
120   }
121 
122 
123   // Get the tile coordinates. Zoomify requests are of the form r-x-y.jpg
124   // where r is the resolution number and x and y are the tile coordinates
125   Tokenizer izer( suffix, "-" );
126   int resolution=0, x=0, y=0;
127   if( izer.hasMoreTokens() ) resolution = atoi( izer.nextToken().c_str() );
128   if( izer.hasMoreTokens() ) x = atoi( izer.nextToken().c_str() );
129   if( izer.hasMoreTokens() ) y = atoi( izer.nextToken().c_str() );
130 
131   // Bump up to take account of any levels too small for Zoomify
132   resolution += discard;
133 
134   if( session->loglevel >= 2 ){
135     *(session->logfile) << "Zoomify :: Tile request for resolution:"
136 			<< resolution << " at x:" << x << ", y:" << y << endl;
137   }
138 
139 
140   // Get the width and height for the requested resolution
141   width = (*session->image)->getImageWidth(numResolutions-resolution-1);
142   height = (*session->image)->getImageHeight(numResolutions-resolution-1);
143 
144 
145   // Get the width of the tiles and calculate the number
146   // of tiles in each direction
147   unsigned int rem_x = width % tw;
148   unsigned int ntlx = (width / tw) + (rem_x == 0 ? 0 : 1);
149 
150 
151   // Calculate the tile index for this resolution from our x, y
152   unsigned int tile = y*ntlx + x;
153 
154 
155   // Simply pass this on to our JTL send command
156   JTL jtl;
157   jtl.send( session, resolution, tile );
158 
159 
160   // Total Zoomify response time
161   if( session->loglevel >= 2 ){
162     *(session->logfile) << "Zoomify :: Total command time " << command_timer.getTime() << " microseconds" << endl;
163   }
164 
165 
166 }
167