1 /*
2     IIP OJB Command Handler Class Member Functions
3 
4     Copyright (C) 2006-2019 Ruven Pillay.
5 
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 3 of the License, or
9     (at your option) any later version.
10 
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15 
16     You should have received a copy of the GNU General Public License
17     along with this program; if not, write to the Free Software Foundation,
18     Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
19 */
20 
21 
22 #include "Task.h"
23 #include <iostream>
24 #include <algorithm>
25 
26 
27 using namespace std;
28 
29 
30 
run(Session * s,const std::string & a)31 void OBJ::run( Session* s, const std::string& a )
32 {
33 
34   argument = a;
35   // Convert to lower case the argument supplied to the OBJ command
36   transform( argument.begin(), argument.end(), argument.begin(), ::tolower );
37 
38   session = s;
39 
40   // Log this
41   if( session->loglevel >= 3 ) *(session->logfile) << "OBJ :: " << argument << " to be handled" << endl;
42 
43   // Time this command
44   if( session->loglevel >= 2 ) command_timer.start();
45 
46 
47   if( argument == "iip,1.0" ) iip();
48   else if( argument == "basic-info" ){
49     iip_server();
50     max_size();
51     resolution_number();
52     colorspace( "*,*" );
53   }
54   else if( argument == "iip-server" ) iip_server();
55   // IIP optional commands
56   else if( argument == "iip-opt-comm" ) session->response->addResponse( "IIP-opt-comm:CVT CNT QLT JTL JTLS WID HEI RGN MINMAX SHD CMP INV CTW" );
57   // IIP optional objects
58   else if( argument == "iip-opt-obj" ) session->response->addResponse( "IIP-opt-obj:Horizontal-views Vertical-views Tile-size Bits-per-channel Min-Max-sample-values Resolutions" );
59   // Resolution-number
60   else if( argument == "resolution-number" ) resolution_number();
61   // Max-size
62   else if( argument == "max-size" ) max_size();
63   // Tile-size
64   else if( argument == "tile-size" ) tile_size();
65   // Bits per pixel
66   else if( argument == "bits-per-channel" ) bits_per_channel();
67   // Vertical-views
68   else if( argument == "vertical-views" ) vertical_views();
69   // Horizontal-views
70   else if( argument == "horizontal-views" ) horizontal_views();
71   // Minimum and maximum provided by TIFF tags
72   else if( argument == "min-max-sample-values" ) min_max_values();
73   // List of available resolutions
74   else if( argument == "resolutions" ) resolutions();
75 
76   // Colorspace
77   /* The request can have a suffix, which we don't need, so do a
78      like scan
79   */
80   else if( argument.find( "colorspace" ) != string::npos ){
81     colorspace( "*,*" );
82   }
83 
84   // Image Metadata
85   else if( argument == "summary-info" ){
86 
87     metadata( "copyright" );
88     metadata( "subject" );
89     metadata( "author" );
90     metadata( "create-dtm" );
91     metadata( "app-name" );
92   }
93 
94   else if( argument == "copyright" || argument == "title" ||
95 	   argument == "subject" || argument == "author" ||
96 	   argument == "keywords" || argument == "comment" ||
97 	   argument == "last-author" || argument == "rev-number" ||
98 	   argument == "edit-time" || argument == "last-printed" ||
99 	   argument == "create-dtm" || argument == "last-save-dtm" ||
100 	   argument == "app-name" ){
101 
102     metadata( argument );
103   }
104 
105 
106   // None of the above!
107   else{
108 
109     if( session->loglevel >= 1 ){
110       *(session->logfile) << "OBJ :: Unsupported argument: " << argument << " received" << endl;
111     }
112 
113     // Unsupported object error code is 3 2
114     session->response->setError( "3 2", argument );
115   }
116 
117 
118   if( session->loglevel >= 2 ){
119     *(session->logfile) << "OBJ :: Total command time " << command_timer.getTime() << " microseconds" << endl;
120   }
121 
122 
123 }
124 
125 
126 
iip()127 void OBJ::iip(){
128   session->response->setProtocol( "IIP:1.0" );
129 }
130 
131 
iip_server()132 void OBJ::iip_server(){
133   // The binary capability code is 1000001 == 65 in integer
134   // ie can do CVT jpeg and JTL, but no transforms
135   session->response->addResponse( "IIP-server:3.65" );
136 }
137 
138 
max_size()139 void OBJ::max_size(){
140   checkImage();
141   int x = (*session->image)->getImageWidth();
142   int y = (*session->image)->getImageHeight();
143 
144   // For 90 and 270 rotation swap width and height
145   if( (int)((session->view)->getRotation()) % 180 == 90 ){
146     unsigned int tmp = x;
147     x = y;
148     y = tmp;
149   }
150 
151   if( session->loglevel >= 2 ){
152     *(session->logfile) << "OBJ :: Max-size is " << x << " " << y << endl;
153   }
154   session->response->addResponse( "Max-size", x, y );
155 }
156 
157 
resolution_number()158 void OBJ::resolution_number(){
159 
160   checkImage();
161   int no_res = (*session->image)->getNumResolutions();
162   if( session->loglevel >= 2 ){
163     *(session->logfile) << "OBJ :: Resolution-number handler returning " << no_res << endl;
164   }
165   session->response->addResponse( "Resolution-number", no_res );
166 
167 }
168 
169 
tile_size()170 void OBJ::tile_size(){
171   checkImage();
172 
173   int x = (*session->image)->getTileWidth();
174   int y = (*session->image)->getTileHeight();
175   if( session->loglevel >= 2 ){
176     *(session->logfile) << "OBJ :: Tile-size is " << x << " " << y << endl;
177   }
178   session->response->addResponse( "Tile-size", x, y );
179 }
180 
181 
bits_per_channel()182 void OBJ::bits_per_channel(){
183 
184   checkImage();
185   int bpc = (*session->image)->getNumBitsPerPixel();
186   if( session->loglevel >= 2 ){
187     *(session->logfile) << "OBJ :: Bits-per-channel handler returning " << bpc << endl;
188   }
189   session->response->addResponse( "Bits-per-channel", bpc );
190 
191 }
192 
193 
vertical_views()194 void OBJ::vertical_views(){
195   checkImage();
196   list <int> views = (*session->image)->getVerticalViewsList();
197   list <int> :: const_iterator i;
198   string tmp = "Vertical-views:";
199   char val[8];
200   for( i = views.begin(); i != views.end(); i++ ){
201     snprintf( val, 8, "%d ", *i );
202     tmp += val;
203   }
204   // Chop off the final space
205   tmp.resize( tmp.length() - 1 );
206   session->response->addResponse( tmp );
207 }
208 
209 
horizontal_views()210 void OBJ::horizontal_views(){
211   checkImage();
212   list <int> views = (*session->image)->getHorizontalViewsList();
213   list <int> :: const_iterator i;
214   string tmp = "Horizontal-views:";
215   char val[8];
216   for( i = views.begin(); i != views.end(); i++ ){
217     snprintf( val, 8, "%d ", *i );
218     tmp += val;
219   }
220   // Chop off the final space
221   tmp.resize( tmp.length() - 1 );
222   session->response->addResponse( tmp );
223 }
224 
225 
min_max_values()226 void OBJ::min_max_values(){
227 
228   checkImage();
229   unsigned int n = (*session->image)->getNumChannels();
230   string tmp = "Min-Max-sample-values:";
231   char val[24];
232   float minimum, maximum;
233   for( unsigned int i=0; i<n ; i++ ){
234     minimum = (*session->image)->getMinValue(i);
235     maximum = (*session->image)->getMaxValue(i);
236     snprintf( val, 24, " %.9g ", minimum );
237     tmp += val;
238     snprintf( val, 24, " %.9g ", maximum );
239     tmp += val;
240   }
241   // Chop off the final space
242   tmp.resize( tmp.length() - 1 );
243   session->response->addResponse( tmp );
244   if( session->loglevel >= 2 ){
245     *(session->logfile) << "OBJ :: Min-Max-sample-values handler returning " << tmp << endl;
246   }
247 
248 }
249 
250 
resolutions()251 void OBJ::resolutions(){
252 
253   checkImage();
254   char val[32];
255   int num_res = (*session->image)->getNumResolutions();
256 
257   string tmp = "Resolutions:";
258   for( int i=num_res-1; i>=0; i-- ){
259     snprintf( val, 32, "%d %d", (*session->image)->image_widths[i], (*session->image)->image_heights[i] );
260     tmp += val;
261     if( i>0 ) tmp += ",";
262   }
263   session->response->addResponse( tmp );
264   if( session->loglevel >= 2 ){
265     *(session->logfile) << "OBJ :: Resolutions handler returning " << tmp << endl;
266   }
267 }
268 
269 
colorspace(std::string arg)270 void OBJ::colorspace( std::string arg ){
271 
272   checkImage();
273 
274   /* Assign the colourspace tag: 1 for greyscale, 3 for RGB and
275      a colourspace of 4 to LAB images
276      WARNING: LAB support is an extension and is not in the
277      IIP protocol standard (as of version 1.05)
278   */
279   const char *planes = "3 0 1 2";
280   int calibrated = 0;
281   int colourspace;
282   if( (*session->image)->getColourSpace() == CIELAB ){
283     colourspace = 4;
284     calibrated = 1;
285   }
286   else if( (*session->image)->getColourSpace() == GREYSCALE ){
287     colourspace = 1;
288     planes = "1 0";
289   }
290   else colourspace = 3;
291 
292   int no_res = (*session->image)->getNumResolutions();
293   char tmp[41];
294   snprintf( tmp, 41, "Colorspace,0-%d,0:%d 0 %d %s", no_res-1,
295 	    calibrated, colourspace, planes );
296 
297   if( session->loglevel >= 2 ){
298     *(session->logfile) << "OBJ :: Colourspace handler returning " << tmp << endl;
299   }
300 
301   session->response->addResponse( tmp );
302 }
303 
304 
metadata(string field)305 void OBJ::metadata( string field ){
306 
307   checkImage();
308 
309   string metadata = (*session->image)->getMetadata( field );
310   if( session->loglevel >= 3 ){
311     *(session->logfile) << "OBJ :: " << field << " handler returning '" << metadata << "'" << endl;
312   }
313 
314   if( metadata.length() ){
315     session->response->addResponse( field, metadata );
316   }
317 
318 
319 }
320