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 ()
171 DeepZoomImageTileSource::Abort ()
173 if (get_resource_aborter
)
174 get_resource_aborter
->Cancel ();
176 XML_ParserFree (parser
);
181 DeepZoomImageTileSource::GetTileLayer (int level
, int x
, int y
, Uri
*uri
)
183 //check if there tile is listed in DisplayRects
190 frexp ((double) MAX (GetImageWidth (), GetImageHeight ()), &layers
);
192 while ((cur
= (DisplayRect
*)g_list_nth_data (display_rects
, i
))) {
195 if (!(cur
->min_level
<= level
&& level
<= cur
->max_level
))
198 int vtilesize
= GetTileWidth () * (layers
+ 1 - level
);
199 Rect virtualtile
= Rect (x
* vtilesize
, y
* vtilesize
, vtilesize
, vtilesize
);
200 if (cur
->rect
.IntersectsWith (virtualtile
)) {
210 const Uri
*baseUri
= GetValue (DeepZoomImageTileSource::UriSourceProperty
)->AsUri ();
211 const char *filename
, *ext
;
217 if ((filename
= strrchr (baseUri
->path
, '/')))
220 filename
= baseUri
->path
;
222 if (!(ext
= strrchr (filename
, '.')))
225 image
= g_strdup_printf ("%.*s_files/%d/%d_%d.%s", ext
- filename
, filename
, level
, x
, y
, format
);
227 Uri::Copy (baseUri
, uri
);
228 uri
->Combine (image
);
235 resource_notify (NotifyType type
, gint64 args
, gpointer user_data
)
237 DeepZoomImageTileSource
*dzits
= (DeepZoomImageTileSource
*)user_data
;
238 if (type
== NotifyFailed
)
239 dzits
->DownloaderFailed ();
240 else if (type
== NotifyCompleted
)
241 dzits
->DownloaderComplete ();
245 dz_write (void *buffer
, gint32 offset
, gint32 n
, gpointer data
)
247 DeepZoomImageTileSource
*dzits
= (DeepZoomImageTileSource
*) data
;
248 dzits
->XmlWrite ((char *) buffer
, offset
, n
);
252 DeepZoomImageTileSource::XmlWrite (char* buffer
, gint32 offset
, gint32 n
)
256 LOG_MSI ("Start parsing DeepZoom\n");
257 parser
= XML_ParserCreate (NULL
);
258 XML_SetElementHandler (parser
, start_element
, end_element
);
259 DZParserinfo
*info
= new DZParserinfo ();
261 XML_SetUserData (parser
, info
);
264 if (!XML_Parse (parser
, buffer
, n
, 0)) {
265 printf ("Parser error at line %d:\n%s\n", (int)XML_GetCurrentLineNumber (parser
), XML_ErrorString(XML_GetErrorCode(parser
)));
272 DeepZoomImageTileSource::Download ()
274 LOG_MSI ("DZITS::Download ()\n");
278 Application
*current
= Application::GetCurrent ();
279 Uri
*uri
= GetUriSource ();
281 if (current
&& uri
) {
283 get_resource_aborter
= new Cancellable ();
284 current
->GetResource (GetResourceBase(), uri
, resource_notify
, dz_write
, MediaPolicy
, get_resource_aborter
, this);
289 DeepZoomImageTileSource::DownloaderComplete ()
291 //set isFinal for the parser to complete
292 if (!XML_Parse (parser
, NULL
, 0, 1)) {
293 printf ("Parser error at line %d:\n%s\n", (int)XML_GetCurrentLineNumber (parser
), XML_ErrorString(XML_GetErrorCode(parser
)));
299 DZParserinfo
*info
= (DZParserinfo
*)XML_GetUserData (parser
);
301 if (!info
->isCollection
) {
302 SetImageWidth (info
->image_width
);
303 SetImageHeight (info
->image_height
);
304 SetTileOverlap (info
->overlap
);
305 display_rects
= info
->display_rects
;
307 subimages
= info
->sub_images
;
308 isCollection
= info
->isCollection
;
309 maxLevel
= info
->max_level
;
312 SetTileWidth (info
->tile_size
);
313 SetTileHeight (info
->tile_size
);
314 format
= g_strdup (info
->format
);
318 LOG_MSI ("Done parsing...\n");
320 XML_ParserFree (parser
);
324 parsed_callback (cb_userdata
);
328 DeepZoomImageTileSource::DownloaderFailed ()
330 LOG_MSI ("DZITS::dl failed\n");
332 failed_callback (cb_userdata
);
336 DeepZoomImageTileSource::UriSourceChanged ()
344 if (sourcechanged_callback
)
345 sourcechanged_callback (cb_userdata
);
349 DeepZoomImageTileSource::OnPropertyChanged (PropertyChangedEventArgs
*args
, MoonError
*error
)
351 if (args
->GetId () == DeepZoomImageTileSource::UriSourceProperty
) {
356 if (args
->GetProperty ()->GetOwnerType () != Type::DEEPZOOMIMAGETILESOURCE
) {
357 DependencyObject::OnPropertyChanged (args
, error
);
361 NotifyListenersOfPropertyChange (args
, error
);
366 start_element (void *data
, const char *el
, const char **attr
)
368 DZParserinfo
*info
= (DZParserinfo
*)data
;
370 if (info
->skip
>= 0) {
374 switch (info
->depth
) {
376 //Image or Collection
377 if (!g_ascii_strcasecmp ("Image", el
)) {
378 info
->isCollection
= false;
380 for (i
= 0; attr
[i
]; i
+=2)
381 if (!g_ascii_strcasecmp ("Format", attr
[i
]))
382 info
->format
= g_strdup (attr
[i
+1]);
383 else if (!g_ascii_strcasecmp ("TileSize", attr
[i
]))
384 info
->tile_size
= atoi (attr
[i
+1]);
385 else if (!g_ascii_strcasecmp ("Overlap", attr
[i
]))
386 info
->overlap
= atoi (attr
[i
+1]);
388 LOG_MSI ("\tunparsed attr %s: %s\n", attr
[i
], attr
[i
+1]);
389 } else if (!g_ascii_strcasecmp ("Collection", el
)) {
390 info
->isCollection
= true;
392 for (i
= 0; attr
[i
]; i
+=2)
393 if (!g_ascii_strcasecmp ("Format", attr
[i
]))
394 info
->format
= g_strdup (attr
[i
+1]);
395 else if (!g_ascii_strcasecmp ("TileSize", attr
[i
]))
396 info
->tile_size
= atoi (attr
[i
+1]);
397 else if (!g_ascii_strcasecmp ("MaxLevel", attr
[i
]))
398 info
->max_level
= atoi (attr
[i
+1]);
400 LOG_MSI ("\tunparsed attr %s: %s\n", attr
[i
], attr
[i
+1]);
402 printf ("Unexpected element %s\n", el
);
407 if (!info
->isCollection
) {
408 //Size or DisplayRects
409 if (!g_ascii_strcasecmp ("Size", el
)) {
411 for (i
= 0; attr
[i
]; i
+=2)
412 if (!g_ascii_strcasecmp ("Width", attr
[i
]))
413 info
->image_width
= atol (attr
[i
+1]);
414 else if (!g_ascii_strcasecmp ("Height", attr
[i
]))
415 info
->image_height
= atol (attr
[i
+1]);
417 LOG_MSI ("\tunparsed attr %s: %s\n", attr
[i
], attr
[i
+1]);
418 } else if (!g_ascii_strcasecmp ("DisplayRects", el
)) {
419 //no attributes, only contains DisplayRect element
421 printf ("Unexpected element %s\n", el
);
425 if (!g_ascii_strcasecmp ("Items", el
)) {
426 //no attributes, only contains <I> elements
428 printf ("Unexpected element %d %s\n", info
->depth
, el
);
434 if (!info
->isCollection
) {
436 if (!g_ascii_strcasecmp ("DisplayRect", el
)) {
437 long min_level
, max_level
;
439 for (i
= 0; attr
[i
]; i
+=2)
440 if (!g_ascii_strcasecmp ("MinLevel", attr
[i
]))
441 min_level
= atol (attr
[i
+1]);
442 else if (!g_ascii_strcasecmp ("MaxLevel", attr
[i
]))
443 max_level
= atol (attr
[i
+1]);
445 LOG_MSI ("\tunparsed arg %s: %s\n", attr
[i
], attr
[i
+1]);
446 info
->current_rect
= new DisplayRect (min_level
, max_level
);
448 printf ("Unexpected element %s\n", el
);
452 if (!g_ascii_strcasecmp ("I", el
)) {
453 info
->current_subimage
= new SubImage ();
455 for (i
= 0; attr
[i
]; i
+=2)
456 if (!g_ascii_strcasecmp ("N", attr
[i
]))
457 info
->current_subimage
->n
= atoi (attr
[i
+1]);
458 else if (!g_ascii_strcasecmp ("Id", attr
[i
]))
459 info
->current_subimage
->id
= atoi (attr
[i
+1]);
460 else if (!g_ascii_strcasecmp ("Source", attr
[i
])) {
461 info
->current_subimage
->source
= new Uri ();
462 info
->current_subimage
->source
->Parse (attr
[i
+1]);
464 LOG_MSI ("\tunparsed arg %s: %s\n", attr
[i
], attr
[i
+1]);
467 printf ("Unexpected element %d %s\n", info
->depth
, el
);
473 if (!info
->isCollection
) {
475 if (!g_ascii_strcasecmp ("Rect", el
)) {
476 if (!info
->current_rect
) {
481 for (i
= 0; attr
[i
]; i
+=2)
482 if (!g_ascii_strcasecmp ("X", attr
[i
]))
483 info
->current_rect
->rect
.x
= (double)atol (attr
[i
+1]);
484 else if (!g_ascii_strcasecmp ("Y", attr
[i
]))
485 info
->current_rect
->rect
.y
= (double)atol (attr
[i
+1]);
486 else if (!g_ascii_strcasecmp ("Width", attr
[i
]))
487 info
->current_rect
->rect
.width
= (double)atol (attr
[i
+1]);
488 else if (!g_ascii_strcasecmp ("Height", attr
[i
]))
489 info
->current_rect
->rect
.height
= (double)atol (attr
[i
+1]);
491 LOG_MSI ("\tunparsed attr %s: %s\n", attr
[i
], attr
[i
+1]);
492 info
->display_rects
= g_list_append (info
->display_rects
, info
->current_rect
);
493 info
->current_rect
= NULL
;
495 printf ("Unexpected element %s\n", el
);
499 if (!g_ascii_strcasecmp ("Size", el
)) {
500 if (!info
->current_subimage
) {
505 info
->current_subimage
->has_size
= true;
508 for (i
= 0; attr
[i
]; i
+=2)
509 if (!g_ascii_strcasecmp ("Width", attr
[i
]))
510 info
->current_subimage
->width
= atol (attr
[i
+1]);
511 else if (!g_ascii_strcasecmp ("Height", attr
[i
]))
512 info
->current_subimage
->height
= atol (attr
[i
+1]);
514 LOG_MSI ("\tunparsed attr %s.%s: %s\n", el
, attr
[i
], attr
[i
+1]);
515 } else if (!g_ascii_strcasecmp ("Viewport", el
)) {
516 if (!info
->current_subimage
) {
521 info
->current_subimage
->has_viewport
= true;
524 for (i
= 0; attr
[i
]; i
+=2)
525 if (!g_ascii_strcasecmp ("X", attr
[i
]))
526 info
->current_subimage
->vp_x
= g_ascii_strtod (attr
[i
+1], NULL
);
527 else if (!g_ascii_strcasecmp ("Y", attr
[i
]))
528 info
->current_subimage
->vp_y
= g_ascii_strtod (attr
[i
+1], NULL
);
529 else if (!g_ascii_strcasecmp ("Width", attr
[i
]))
530 info
->current_subimage
->vp_w
= g_ascii_strtod (attr
[i
+1], NULL
);
532 LOG_MSI ("\tunparsed attr %s: %s\n", attr
[i
], attr
[i
+1]);
534 printf ("Unexpected element %s\n", el
);
546 DeepZoomImageTileSource::EndElement (void *data
, const char *el
)
548 DZParserinfo
*info
= (DZParserinfo
*)data
;
551 if (info
->skip
< 0) {
552 switch (info
->depth
) {
554 if (info
->isCollection
)
555 if (!g_ascii_strcasecmp ("I", el
)) {
556 DeepZoomImageTileSource
*subsource
= new DeepZoomImageTileSource (info
->current_subimage
->source
, TRUE
);
557 MultiScaleSubImage
*subi
= new MultiScaleSubImage (info
->source
->GetUriSource (),
559 info
->current_subimage
->id
,
560 info
->current_subimage
->n
);
561 subsource
->SetImageWidth (info
->current_subimage
->width
);
562 subsource
->SetImageHeight (info
->current_subimage
->height
);
563 subsource
->format
= info
->format
;
564 if (info
->current_subimage
->has_viewport
) {
565 subi
->SetViewportOrigin (new Point (info
->current_subimage
->vp_x
, info
->current_subimage
->vp_y
));
566 subi
->SetViewportWidth (info
->current_subimage
->vp_w
);
569 if (info
->current_subimage
->has_size
) {
570 subi
->SetValue (MultiScaleSubImage::AspectRatioProperty
, Value ((double)info
->current_subimage
->width
/(double)info
->current_subimage
->height
));
572 info
->sub_images
= g_list_append (info
->sub_images
, subi
);
573 info
->current_subimage
= NULL
;
579 if (info
->skip
== info
->depth
)
584 end_element (void *data
, const char *el
)
586 DZParserinfo
*info
= (DZParserinfo
*)data
;
587 DeepZoomImageTileSource
*dzits
= (DeepZoomImageTileSource
*)info
->source
;
589 g_assert ("That's wrong...\n");
590 dzits
->EndElement (info
, el
);