2009-12-04 Jeffrey Stedfast <fejj@novell.com>
[moon.git] / src / deepzoomimagetilesource.cpp
blob7a13e681f83aa8a99fc377823efb9ef2fb8c9687
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3 * deepzoomimagetilesource.cpp
5 * Contact:
6 * Moonlight List (moonlight-list@lists.ximian.com)
8 * Copyright 2007,2009 Novell, Inc. (http://www.novell.com)
10 * See the LICENSE file included with the distribution for details.
14 #include <config.h>
16 #include <stdio.h>
17 #include <math.h>
19 #include "debug.h"
20 #include "runtime.h"
22 #include "deepzoomimagetilesource.h"
23 #include "multiscalesubimage.h"
24 #include "uri.h"
25 #include "file-downloader.h"
27 class DisplayRect
29 public:
30 long min_level;
31 long max_level;
32 Rect rect;
34 DisplayRect (long minLevel, long maxLevel)
36 min_level = minLevel;
37 max_level = maxLevel;
41 class SubImage
43 public:
44 int id;
45 int n;
46 Uri *source;
47 long width;
48 long height;
49 double vp_x;
50 double vp_y;
51 double vp_w;
53 bool has_viewport;
54 bool has_size;
56 SubImage ()
58 source = NULL;
59 has_viewport = false;
60 has_size = false;
64 class DZParserinfo
66 public:
67 int depth;
68 int skip;
69 bool error;
70 DeepZoomImageTileSource *source;
72 bool isCollection;
74 //Image attributes
75 int overlap;
76 long image_width, image_height;
77 DisplayRect *current_rect;
78 GList *display_rects;
80 //Collection attributes
81 int max_level;
82 SubImage *current_subimage;
83 GList *sub_images;
85 //Common attributes
86 char *format;
87 int tile_size;
90 DZParserinfo ()
92 depth = 0;
93 skip = -1;
94 error = false;
95 format = NULL;
96 image_width = image_height = tile_size = overlap = 0;
97 current_rect = NULL;
98 display_rects = NULL;
99 sub_images = NULL;
100 current_subimage = NULL;
101 source = NULL;
105 void start_element (void *data, const char *el, const char **attr);
106 void end_element (void *data, const char *el);
108 bool
109 get_tile_layer (int level, int x, int y, Uri *uri, void *userdata)
111 return ((DeepZoomImageTileSource *)userdata)->GetTileLayer (level, x, y, uri);
114 void
115 DeepZoomImageTileSource::Init ()
117 SetObjectType (Type::DEEPZOOMIMAGETILESOURCE);
119 downloaded = false;
120 parsed = false;
121 format = NULL;
122 get_tile_func = get_tile_layer;
123 display_rects = NULL;
124 parsed_callback = NULL;
125 failed_callback = NULL;
126 sourcechanged_callback = NULL;
127 isCollection = false;
128 subimages = NULL;
129 nested = false;
130 get_resource_aborter = NULL;
131 parser = NULL;
134 DeepZoomImageTileSource::DeepZoomImageTileSource ()
136 Init ();
139 DeepZoomImageTileSource::DeepZoomImageTileSource (Uri *uri, bool nested)
141 Init ();
142 this->nested = nested;
143 if (uri)
144 SetUriSource (uri);
147 DeepZoomImageTileSource::~DeepZoomImageTileSource ()
149 Abort ();
150 g_free (format);
151 delete get_resource_aborter;
154 void
155 DeepZoomImageTileSource::Abort ()
157 if (get_resource_aborter)
158 get_resource_aborter->Cancel ();
159 if (parser)
160 XML_ParserFree (parser);
161 parser = NULL;
164 bool
165 DeepZoomImageTileSource::GetTileLayer (int level, int x, int y, Uri *uri)
167 //check if there tile is listed in DisplayRects
168 if (display_rects) {
169 DisplayRect *cur;
170 int i =0;
171 bool found = false;
172 int layers;
174 frexp ((double) MAX (GetImageWidth (), GetImageHeight ()), &layers);
176 while ((cur = (DisplayRect*)g_list_nth_data (display_rects, i))) {
177 i++;
179 if (!(cur->min_level <= level && level <= cur->max_level))
180 continue;
182 int vtilesize = GetTileWidth () * (layers + 1 - level);
183 Rect virtualtile = Rect (x * vtilesize, y * vtilesize, vtilesize, vtilesize);
184 if (cur->rect.IntersectsWith (virtualtile)) {
185 found = true;
186 break;
190 if (!found)
191 return false;
194 const Uri *baseUri = GetValue (DeepZoomImageTileSource::UriSourceProperty)->AsUri ();
195 const char *filename, *ext;
196 char *image;
198 if (!baseUri)
199 return false;
201 if ((filename = strrchr (baseUri->path, '/')))
202 filename ++;
203 else
204 filename = baseUri->path;
206 if (!(ext = strrchr (filename, '.')))
207 return false;
209 image = g_strdup_printf ("%.*s_files/%d/%d_%d.%s", (int) (ext - filename), filename, level, x, y, format);
211 Uri::Copy (baseUri, uri);
212 uri->Combine (image);
213 g_free (image);
215 return true;
218 static void
219 resource_notify (NotifyType type, gint64 args, gpointer user_data)
221 DeepZoomImageTileSource *dzits = (DeepZoomImageTileSource *)user_data;
222 if (type == NotifyFailed)
223 dzits->DownloaderFailed ();
224 else if (type == NotifyCompleted)
225 dzits->DownloaderComplete ();
228 static void
229 dz_write (void *buffer, gint32 offset, gint32 n, gpointer data)
231 DeepZoomImageTileSource *dzits = (DeepZoomImageTileSource *) data;
232 dzits->XmlWrite ((char *) buffer, offset, n);
235 void
236 DeepZoomImageTileSource::XmlWrite (char* buffer, gint32 offset, gint32 n)
238 if (offset == 0) {
239 //Init xml parser
240 LOG_MSI ("Start parsing DeepZoom\n");
241 parser = XML_ParserCreate (NULL);
242 XML_SetElementHandler (parser, start_element, end_element);
243 DZParserinfo *info = new DZParserinfo ();
244 info->source = this;
245 XML_SetUserData (parser, info);
248 if (!XML_Parse (parser, buffer, n, 0)) {
249 printf ("Parser error at line %d:\n%s\n", (int)XML_GetCurrentLineNumber (parser), XML_ErrorString(XML_GetErrorCode(parser)));
250 Abort ();
251 DownloaderFailed ();
255 void
256 DeepZoomImageTileSource::Download ()
258 LOG_MSI ("DZITS::Download ()\n");
259 if (downloaded)
260 return;
262 Application *current = Application::GetCurrent ();
263 Uri *uri = GetUriSource ();
265 if (current && uri) {
266 downloaded = true;
267 if (get_resource_aborter)
268 delete get_resource_aborter;
269 get_resource_aborter = new Cancellable ();
270 current->GetResource (GetResourceBase(), uri, resource_notify, dz_write, MediaPolicy, get_resource_aborter, this);
274 void
275 DeepZoomImageTileSource::DownloaderComplete ()
277 //set isFinal for the parser to complete
278 if (!XML_Parse (parser, NULL, 0, 1)) {
279 printf ("Parser error at line %d:\n%s\n", (int)XML_GetCurrentLineNumber (parser), XML_ErrorString(XML_GetErrorCode(parser)));
280 Abort ();
281 DownloaderFailed ();
282 return;
285 DZParserinfo *info = (DZParserinfo *)XML_GetUserData (parser);
287 if (!info->isCollection) {
288 SetImageWidth (info->image_width);
289 SetImageHeight (info->image_height);
290 SetTileOverlap (info->overlap);
291 display_rects = info->display_rects;
292 } else {
293 subimages = info->sub_images;
294 isCollection = info->isCollection;
295 maxLevel = info->max_level;
298 SetTileWidth (info->tile_size);
299 SetTileHeight (info->tile_size);
300 format = g_strdup (info->format);
302 parsed = true;
304 LOG_MSI ("Done parsing...\n");
306 XML_ParserFree (parser);
307 parser = NULL;
309 if (parsed_callback)
310 parsed_callback (cb_userdata);
313 void
314 DeepZoomImageTileSource::DownloaderFailed ()
316 LOG_MSI ("DZITS::dl failed\n");
317 if (failed_callback)
318 failed_callback (cb_userdata);
321 void
322 DeepZoomImageTileSource::UriSourceChanged ()
324 parsed = false;
325 downloaded = false;
326 if (!nested) {
327 Download ();
330 if (sourcechanged_callback)
331 sourcechanged_callback (cb_userdata);
334 void
335 DeepZoomImageTileSource::OnPropertyChanged (PropertyChangedEventArgs *args, MoonError *error)
337 if (args->GetId () == DeepZoomImageTileSource::UriSourceProperty) {
338 Abort ();
339 UriSourceChanged ();
342 if (args->GetProperty ()->GetOwnerType () != Type::DEEPZOOMIMAGETILESOURCE) {
343 DependencyObject::OnPropertyChanged (args, error);
344 return;
347 NotifyListenersOfPropertyChange (args, error);
350 //DeepZoomParsing
351 void
352 start_element (void *data, const char *el, const char **attr)
354 DZParserinfo *info = (DZParserinfo*)data;
356 if (info->skip >= 0) {
357 (info->depth)++;
358 return;
360 switch (info->depth) {
361 case 0:
362 //Image or Collection
363 if (!g_ascii_strcasecmp ("Image", el)) {
364 info->isCollection = false;
365 int i;
366 for (i = 0; attr[i]; i+=2)
367 if (!g_ascii_strcasecmp ("Format", attr[i]))
368 info->format = g_strdup (attr[i+1]);
369 else if (!g_ascii_strcasecmp ("TileSize", attr[i]))
370 info->tile_size = atoi (attr[i+1]);
371 else if (!g_ascii_strcasecmp ("Overlap", attr[i]))
372 info->overlap = atoi (attr[i+1]);
373 else
374 LOG_MSI ("\tunparsed attr %s: %s\n", attr[i], attr[i+1]);
375 } else if (!g_ascii_strcasecmp ("Collection", el)) {
376 info->isCollection = true;
377 int i;
378 for (i = 0; attr[i]; i+=2)
379 if (!g_ascii_strcasecmp ("Format", attr[i]))
380 info->format = g_strdup (attr[i+1]);
381 else if (!g_ascii_strcasecmp ("TileSize", attr[i]))
382 info->tile_size = atoi (attr[i+1]);
383 else if (!g_ascii_strcasecmp ("MaxLevel", attr[i]))
384 info->max_level = atoi (attr[i+1]);
385 else
386 LOG_MSI ("\tunparsed attr %s: %s\n", attr[i], attr[i+1]);
387 } else {
388 printf ("Unexpected element %s\n", el);
389 info->error = true;
391 break;
392 case 1:
393 if (!info->isCollection) {
394 //Size or DisplayRects
395 if (!g_ascii_strcasecmp ("Size", el)) {
396 int i;
397 for (i = 0; attr[i]; i+=2)
398 if (!g_ascii_strcasecmp ("Width", attr[i]))
399 info->image_width = atol (attr[i+1]);
400 else if (!g_ascii_strcasecmp ("Height", attr[i]))
401 info->image_height = atol (attr[i+1]);
402 else
403 LOG_MSI ("\tunparsed attr %s: %s\n", attr[i], attr[i+1]);
404 } else if (!g_ascii_strcasecmp ("DisplayRects", el)) {
405 //no attributes, only contains DisplayRect element
406 } else {
407 printf ("Unexpected element %s\n", el);
408 info->error = true;
410 } else {
411 if (!g_ascii_strcasecmp ("Items", el)) {
412 //no attributes, only contains <I> elements
413 } else {
414 printf ("Unexpected element %d %s\n", info->depth, el);
415 info->error = true;
418 break;
419 case 2:
420 if (!info->isCollection) {
421 //DisplayRect elts
422 if (!g_ascii_strcasecmp ("DisplayRect", el)) {
423 long min_level = 0, max_level = 0;
424 int i;
425 for (i = 0; attr[i]; i+=2)
426 if (!g_ascii_strcasecmp ("MinLevel", attr[i]))
427 min_level = atol (attr[i+1]);
428 else if (!g_ascii_strcasecmp ("MaxLevel", attr[i]))
429 max_level = atol (attr[i+1]);
430 else
431 LOG_MSI ("\tunparsed arg %s: %s\n", attr[i], attr[i+1]);
432 info->current_rect = new DisplayRect (min_level, max_level);
433 } else {
434 printf ("Unexpected element %s\n", el);
435 info->error = true;
437 } else {
438 if (!g_ascii_strcasecmp ("I", el)) {
439 info->current_subimage = new SubImage ();
440 int i;
441 for (i = 0; attr[i]; i+=2)
442 if (!g_ascii_strcasecmp ("N", attr[i]))
443 info->current_subimage->n = atoi (attr[i+1]);
444 else if (!g_ascii_strcasecmp ("Id", attr[i]))
445 info->current_subimage->id = atoi (attr[i+1]);
446 else if (!g_ascii_strcasecmp ("Source", attr[i])) {
447 info->current_subimage->source = new Uri ();
448 info->current_subimage->source->Parse (attr[i+1]);
449 } else
450 LOG_MSI ("\tunparsed arg %s: %s\n", attr[i], attr[i+1]);
452 } else {
453 printf ("Unexpected element %d %s\n", info->depth, el);
454 info->error = true;
457 break;
458 case 3:
459 if (!info->isCollection) {
460 //Rect elt
461 if (!g_ascii_strcasecmp ("Rect", el)) {
462 if (!info->current_rect) {
463 info->error = true;
464 break;
466 int i;
467 for (i = 0; attr[i]; i+=2)
468 if (!g_ascii_strcasecmp ("X", attr[i]))
469 info->current_rect->rect.x = (double)atol (attr[i+1]);
470 else if (!g_ascii_strcasecmp ("Y", attr[i]))
471 info->current_rect->rect.y = (double)atol (attr[i+1]);
472 else if (!g_ascii_strcasecmp ("Width", attr[i]))
473 info->current_rect->rect.width = (double)atol (attr[i+1]);
474 else if (!g_ascii_strcasecmp ("Height", attr[i]))
475 info->current_rect->rect.height = (double)atol (attr[i+1]);
476 else
477 LOG_MSI ("\tunparsed attr %s: %s\n", attr[i], attr[i+1]);
478 info->display_rects = g_list_append (info->display_rects, info->current_rect);
479 info->current_rect = NULL;
480 } else {
481 printf ("Unexpected element %s\n", el);
482 info->error = true;
484 } else {
485 if (!g_ascii_strcasecmp ("Size", el)) {
486 if (!info->current_subimage) {
487 info->error = true;
488 break;
491 info->current_subimage->has_size = true;
493 int i;
494 for (i = 0; attr [i]; i+=2)
495 if (!g_ascii_strcasecmp ("Width", attr[i]))
496 info->current_subimage->width = atol (attr[i+1]);
497 else if (!g_ascii_strcasecmp ("Height", attr[i]))
498 info->current_subimage->height = atol (attr[i+1]);
499 else
500 LOG_MSI ("\tunparsed attr %s.%s: %s\n", el, attr[i], attr[i+1]);
501 } else if (!g_ascii_strcasecmp ("Viewport", el)) {
502 if (!info->current_subimage) {
503 info->error = true;
504 break;
507 info->current_subimage->has_viewport = true;
509 int i;
510 for (i = 0; attr [i]; i+=2)
511 if (!g_ascii_strcasecmp ("X", attr[i]))
512 info->current_subimage->vp_x = g_ascii_strtod (attr[i+1], NULL);
513 else if (!g_ascii_strcasecmp ("Y", attr[i]))
514 info->current_subimage->vp_y = g_ascii_strtod (attr[i+1], NULL);
515 else if (!g_ascii_strcasecmp ("Width", attr[i]))
516 info->current_subimage->vp_w = g_ascii_strtod (attr[i+1], NULL);
517 else
518 LOG_MSI ("\tunparsed attr %s: %s\n", attr[i], attr[i+1]);
519 } else {
520 printf ("Unexpected element %s\n", el);
521 info->error = true;
524 break;
528 (info->depth)++;
531 void
532 DeepZoomImageTileSource::EndElement (void *data, const char *el)
534 DZParserinfo *info = (DZParserinfo*)data;
535 (info->depth)--;
537 if (info->skip < 0) {
538 switch (info->depth) {
539 case 2:
540 if (info->isCollection)
541 if (!g_ascii_strcasecmp ("I", el)) {
542 DeepZoomImageTileSource *subsource = new DeepZoomImageTileSource (info->current_subimage->source, TRUE);
543 MultiScaleSubImage *subi = new MultiScaleSubImage (info->source->GetUriSource (),
544 subsource,
545 info->current_subimage->id,
546 info->current_subimage->n);
547 subsource->SetImageWidth (info->current_subimage->width);
548 subsource->SetImageHeight (info->current_subimage->height);
549 subsource->format = info->format;
550 if (info->current_subimage->has_viewport) {
551 subi->SetViewportOrigin (new Point (info->current_subimage->vp_x, info->current_subimage->vp_y));
552 subi->SetViewportWidth (info->current_subimage->vp_w);
555 if (info->current_subimage->has_size) {
556 subi->SetValue (MultiScaleSubImage::AspectRatioProperty, Value ((double)info->current_subimage->width/(double)info->current_subimage->height));
558 info->sub_images = g_list_append (info->sub_images, subi);
559 info->current_subimage = NULL;
561 break;
565 if (info->skip == info->depth)
566 info->skip = -1;
569 void
570 end_element (void *data, const char *el)
572 DZParserinfo *info = (DZParserinfo*)data;
573 DeepZoomImageTileSource *dzits = (DeepZoomImageTileSource*)info->source;
574 if (!dzits)
575 g_assert ("That's wrong...\n");
576 dzits->EndElement (info, el);