1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * deepzoomimagetilesource.cpp
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.
22 #include "deepzoomimagetilesource.h"
23 #include "multiscalesubimage.h"
25 #include "file-downloader.h"
34 DisplayRect (long minLevel
, long maxLevel
)
70 DeepZoomImageTileSource
*source
;
76 long image_width
, image_height
;
77 DisplayRect
*current_rect
;
80 //Collection attributes
82 SubImage
*current_subimage
;
96 image_width
= image_height
= tile_size
= overlap
= 0;
100 current_subimage
= NULL
;
105 void start_element (void *data
, const char *el
, const char **attr
);
106 void end_element (void *data
, const char *el
);
109 get_tile_layer (int level
, int x
, int y
, Uri
*uri
, void *userdata
)
111 return ((DeepZoomImageTileSource
*)userdata
)->GetTileLayer (level
, x
, y
, uri
);
115 DeepZoomImageTileSource::Init ()
117 SetObjectType (Type::DEEPZOOMIMAGETILESOURCE
);
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;
130 get_resource_aborter
= NULL
;
134 DeepZoomImageTileSource::DeepZoomImageTileSource ()
139 DeepZoomImageTileSource::DeepZoomImageTileSource (Uri
*uri
, bool nested
)
142 this->nested
= nested
;
143 strip_and_set_uri (uri
);
146 //this is only meant to be used at construct time, if the uri is set from xaml, or using new DeepZoomImageTileSource (Uri)
147 // drt511 shows the new DeepZoomImageTileSource (Uri) behavior
148 // drt509 shows that sources set by setting the DP shouldn't be stripped
149 // http://www.silverlightshow.net/showcase/deepzoom/TestPage.html creates from xaml, and need ot be stripped
152 DeepZoomImageTileSource::strip_and_set_uri (Uri
*uri
)
156 char *s
= uri
->ToString ();
157 Uri stripped
= Uri ();
158 if (g_str_has_prefix (s
, "/"))
159 stripped
.Parse (s
+ 1);
162 SetValue (DeepZoomImageTileSource::UriSourceProperty
, new Value (stripped
));
165 DeepZoomImageTileSource::~DeepZoomImageTileSource ()
169 delete get_resource_aborter
;
173 DeepZoomImageTileSource::Abort ()
175 if (get_resource_aborter
)
176 get_resource_aborter
->Cancel ();
178 XML_ParserFree (parser
);
183 DeepZoomImageTileSource::GetTileLayer (int level
, int x
, int y
, Uri
*uri
)
185 //check if there tile is listed in DisplayRects
192 frexp ((double) MAX (GetImageWidth (), GetImageHeight ()), &layers
);
194 while ((cur
= (DisplayRect
*)g_list_nth_data (display_rects
, i
))) {
197 if (!(cur
->min_level
<= level
&& level
<= cur
->max_level
))
200 int vtilesize
= GetTileWidth () * (layers
+ 1 - level
);
201 Rect virtualtile
= Rect (x
* vtilesize
, y
* vtilesize
, vtilesize
, vtilesize
);
202 if (cur
->rect
.IntersectsWith (virtualtile
)) {
212 const Uri
*baseUri
= GetValue (DeepZoomImageTileSource::UriSourceProperty
)->AsUri ();
213 const char *filename
, *ext
;
219 if ((filename
= strrchr (baseUri
->path
, '/')))
222 filename
= baseUri
->path
;
224 if (!(ext
= strrchr (filename
, '.')))
227 image
= g_strdup_printf ("%.*s_files/%d/%d_%d.%s", ext
- filename
, filename
, level
, x
, y
, format
);
229 Uri::Copy (baseUri
, uri
);
230 uri
->Combine (image
);
237 resource_notify (NotifyType type
, gint64 args
, gpointer user_data
)
239 DeepZoomImageTileSource
*dzits
= (DeepZoomImageTileSource
*)user_data
;
240 if (type
== NotifyFailed
)
241 dzits
->DownloaderFailed ();
242 else if (type
== NotifyCompleted
)
243 dzits
->DownloaderComplete ();
247 dz_write (void *buffer
, gint32 offset
, gint32 n
, gpointer data
)
249 DeepZoomImageTileSource
*dzits
= (DeepZoomImageTileSource
*) data
;
250 dzits
->XmlWrite ((char *) buffer
, offset
, n
);
254 DeepZoomImageTileSource::XmlWrite (char* buffer
, gint32 offset
, gint32 n
)
258 LOG_MSI ("Start parsing DeepZoom\n");
259 parser
= XML_ParserCreate (NULL
);
260 XML_SetElementHandler (parser
, start_element
, end_element
);
261 DZParserinfo
*info
= new DZParserinfo ();
263 XML_SetUserData (parser
, info
);
266 if (!XML_Parse (parser
, buffer
, n
, 0)) {
267 printf ("Parser error at line %d:\n%s\n", (int)XML_GetCurrentLineNumber (parser
), XML_ErrorString(XML_GetErrorCode(parser
)));
274 DeepZoomImageTileSource::Download ()
276 LOG_MSI ("DZITS::Download ()\n");
280 Application
*current
= Application::GetCurrent ();
281 Uri
*uri
= GetUriSource ();
283 if (current
&& uri
) {
285 if (get_resource_aborter
)
286 delete get_resource_aborter
;
287 get_resource_aborter
= new Cancellable ();
288 current
->GetResource (GetResourceBase(), uri
, resource_notify
, dz_write
, MediaPolicy
, get_resource_aborter
, this);
293 DeepZoomImageTileSource::DownloaderComplete ()
295 //set isFinal for the parser to complete
296 if (!XML_Parse (parser
, NULL
, 0, 1)) {
297 printf ("Parser error at line %d:\n%s\n", (int)XML_GetCurrentLineNumber (parser
), XML_ErrorString(XML_GetErrorCode(parser
)));
303 DZParserinfo
*info
= (DZParserinfo
*)XML_GetUserData (parser
);
305 if (!info
->isCollection
) {
306 SetImageWidth (info
->image_width
);
307 SetImageHeight (info
->image_height
);
308 SetTileOverlap (info
->overlap
);
309 display_rects
= info
->display_rects
;
311 subimages
= info
->sub_images
;
312 isCollection
= info
->isCollection
;
313 maxLevel
= info
->max_level
;
316 SetTileWidth (info
->tile_size
);
317 SetTileHeight (info
->tile_size
);
318 format
= g_strdup (info
->format
);
322 LOG_MSI ("Done parsing...\n");
324 XML_ParserFree (parser
);
328 parsed_callback (cb_userdata
);
332 DeepZoomImageTileSource::DownloaderFailed ()
334 LOG_MSI ("DZITS::dl failed\n");
336 failed_callback (cb_userdata
);
340 DeepZoomImageTileSource::UriSourceChanged ()
348 if (sourcechanged_callback
)
349 sourcechanged_callback (cb_userdata
);
353 DeepZoomImageTileSource::OnPropertyChanged (PropertyChangedEventArgs
*args
, MoonError
*error
)
355 if (args
->GetId () == DeepZoomImageTileSource::UriSourceProperty
) {
360 if (args
->GetProperty ()->GetOwnerType () != Type::DEEPZOOMIMAGETILESOURCE
) {
361 DependencyObject::OnPropertyChanged (args
, error
);
365 NotifyListenersOfPropertyChange (args
, error
);
370 start_element (void *data
, const char *el
, const char **attr
)
372 DZParserinfo
*info
= (DZParserinfo
*)data
;
374 if (info
->skip
>= 0) {
378 switch (info
->depth
) {
380 //Image or Collection
381 if (!g_ascii_strcasecmp ("Image", el
)) {
382 info
->isCollection
= false;
384 for (i
= 0; attr
[i
]; i
+=2)
385 if (!g_ascii_strcasecmp ("Format", attr
[i
]))
386 info
->format
= g_strdup (attr
[i
+1]);
387 else if (!g_ascii_strcasecmp ("TileSize", attr
[i
]))
388 info
->tile_size
= atoi (attr
[i
+1]);
389 else if (!g_ascii_strcasecmp ("Overlap", attr
[i
]))
390 info
->overlap
= atoi (attr
[i
+1]);
392 LOG_MSI ("\tunparsed attr %s: %s\n", attr
[i
], attr
[i
+1]);
393 } else if (!g_ascii_strcasecmp ("Collection", el
)) {
394 info
->isCollection
= true;
396 for (i
= 0; attr
[i
]; i
+=2)
397 if (!g_ascii_strcasecmp ("Format", attr
[i
]))
398 info
->format
= g_strdup (attr
[i
+1]);
399 else if (!g_ascii_strcasecmp ("TileSize", attr
[i
]))
400 info
->tile_size
= atoi (attr
[i
+1]);
401 else if (!g_ascii_strcasecmp ("MaxLevel", attr
[i
]))
402 info
->max_level
= atoi (attr
[i
+1]);
404 LOG_MSI ("\tunparsed attr %s: %s\n", attr
[i
], attr
[i
+1]);
406 printf ("Unexpected element %s\n", el
);
411 if (!info
->isCollection
) {
412 //Size or DisplayRects
413 if (!g_ascii_strcasecmp ("Size", el
)) {
415 for (i
= 0; attr
[i
]; i
+=2)
416 if (!g_ascii_strcasecmp ("Width", attr
[i
]))
417 info
->image_width
= atol (attr
[i
+1]);
418 else if (!g_ascii_strcasecmp ("Height", attr
[i
]))
419 info
->image_height
= atol (attr
[i
+1]);
421 LOG_MSI ("\tunparsed attr %s: %s\n", attr
[i
], attr
[i
+1]);
422 } else if (!g_ascii_strcasecmp ("DisplayRects", el
)) {
423 //no attributes, only contains DisplayRect element
425 printf ("Unexpected element %s\n", el
);
429 if (!g_ascii_strcasecmp ("Items", el
)) {
430 //no attributes, only contains <I> elements
432 printf ("Unexpected element %d %s\n", info
->depth
, el
);
438 if (!info
->isCollection
) {
440 if (!g_ascii_strcasecmp ("DisplayRect", el
)) {
441 long min_level
, max_level
;
443 for (i
= 0; attr
[i
]; i
+=2)
444 if (!g_ascii_strcasecmp ("MinLevel", attr
[i
]))
445 min_level
= atol (attr
[i
+1]);
446 else if (!g_ascii_strcasecmp ("MaxLevel", attr
[i
]))
447 max_level
= atol (attr
[i
+1]);
449 LOG_MSI ("\tunparsed arg %s: %s\n", attr
[i
], attr
[i
+1]);
450 info
->current_rect
= new DisplayRect (min_level
, max_level
);
452 printf ("Unexpected element %s\n", el
);
456 if (!g_ascii_strcasecmp ("I", el
)) {
457 info
->current_subimage
= new SubImage ();
459 for (i
= 0; attr
[i
]; i
+=2)
460 if (!g_ascii_strcasecmp ("N", attr
[i
]))
461 info
->current_subimage
->n
= atoi (attr
[i
+1]);
462 else if (!g_ascii_strcasecmp ("Id", attr
[i
]))
463 info
->current_subimage
->id
= atoi (attr
[i
+1]);
464 else if (!g_ascii_strcasecmp ("Source", attr
[i
])) {
465 info
->current_subimage
->source
= new Uri ();
466 info
->current_subimage
->source
->Parse (attr
[i
+1]);
468 LOG_MSI ("\tunparsed arg %s: %s\n", attr
[i
], attr
[i
+1]);
471 printf ("Unexpected element %d %s\n", info
->depth
, el
);
477 if (!info
->isCollection
) {
479 if (!g_ascii_strcasecmp ("Rect", el
)) {
480 if (!info
->current_rect
) {
485 for (i
= 0; attr
[i
]; i
+=2)
486 if (!g_ascii_strcasecmp ("X", attr
[i
]))
487 info
->current_rect
->rect
.x
= (double)atol (attr
[i
+1]);
488 else if (!g_ascii_strcasecmp ("Y", attr
[i
]))
489 info
->current_rect
->rect
.y
= (double)atol (attr
[i
+1]);
490 else if (!g_ascii_strcasecmp ("Width", attr
[i
]))
491 info
->current_rect
->rect
.width
= (double)atol (attr
[i
+1]);
492 else if (!g_ascii_strcasecmp ("Height", attr
[i
]))
493 info
->current_rect
->rect
.height
= (double)atol (attr
[i
+1]);
495 LOG_MSI ("\tunparsed attr %s: %s\n", attr
[i
], attr
[i
+1]);
496 info
->display_rects
= g_list_append (info
->display_rects
, info
->current_rect
);
497 info
->current_rect
= NULL
;
499 printf ("Unexpected element %s\n", el
);
503 if (!g_ascii_strcasecmp ("Size", el
)) {
504 if (!info
->current_subimage
) {
509 info
->current_subimage
->has_size
= true;
512 for (i
= 0; attr
[i
]; i
+=2)
513 if (!g_ascii_strcasecmp ("Width", attr
[i
]))
514 info
->current_subimage
->width
= atol (attr
[i
+1]);
515 else if (!g_ascii_strcasecmp ("Height", attr
[i
]))
516 info
->current_subimage
->height
= atol (attr
[i
+1]);
518 LOG_MSI ("\tunparsed attr %s.%s: %s\n", el
, attr
[i
], attr
[i
+1]);
519 } else if (!g_ascii_strcasecmp ("Viewport", el
)) {
520 if (!info
->current_subimage
) {
525 info
->current_subimage
->has_viewport
= true;
528 for (i
= 0; attr
[i
]; i
+=2)
529 if (!g_ascii_strcasecmp ("X", attr
[i
]))
530 info
->current_subimage
->vp_x
= g_ascii_strtod (attr
[i
+1], NULL
);
531 else if (!g_ascii_strcasecmp ("Y", attr
[i
]))
532 info
->current_subimage
->vp_y
= g_ascii_strtod (attr
[i
+1], NULL
);
533 else if (!g_ascii_strcasecmp ("Width", attr
[i
]))
534 info
->current_subimage
->vp_w
= g_ascii_strtod (attr
[i
+1], NULL
);
536 LOG_MSI ("\tunparsed attr %s: %s\n", attr
[i
], attr
[i
+1]);
538 printf ("Unexpected element %s\n", el
);
550 DeepZoomImageTileSource::EndElement (void *data
, const char *el
)
552 DZParserinfo
*info
= (DZParserinfo
*)data
;
555 if (info
->skip
< 0) {
556 switch (info
->depth
) {
558 if (info
->isCollection
)
559 if (!g_ascii_strcasecmp ("I", el
)) {
560 DeepZoomImageTileSource
*subsource
= new DeepZoomImageTileSource (info
->current_subimage
->source
, TRUE
);
561 MultiScaleSubImage
*subi
= new MultiScaleSubImage (info
->source
->GetUriSource (),
563 info
->current_subimage
->id
,
564 info
->current_subimage
->n
);
565 subsource
->SetImageWidth (info
->current_subimage
->width
);
566 subsource
->SetImageHeight (info
->current_subimage
->height
);
567 subsource
->format
= info
->format
;
568 if (info
->current_subimage
->has_viewport
) {
569 subi
->SetViewportOrigin (new Point (info
->current_subimage
->vp_x
, info
->current_subimage
->vp_y
));
570 subi
->SetViewportWidth (info
->current_subimage
->vp_w
);
573 if (info
->current_subimage
->has_size
) {
574 subi
->SetValue (MultiScaleSubImage::AspectRatioProperty
, Value ((double)info
->current_subimage
->width
/(double)info
->current_subimage
->height
));
576 info
->sub_images
= g_list_append (info
->sub_images
, subi
);
577 info
->current_subimage
= NULL
;
583 if (info
->skip
== info
->depth
)
588 end_element (void *data
, const char *el
)
590 DZParserinfo
*info
= (DZParserinfo
*)data
;
591 DeepZoomImageTileSource
*dzits
= (DeepZoomImageTileSource
*)info
->source
;
593 g_assert ("That's wrong...\n");
594 dzits
->EndElement (info
, el
);