Project

General

Profile

Download (19.5 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
// $Id$
3

    
4
/**
5
 * Copyright (C) 2007 EDIT
6
 * European Distributed Institute of Taxonomy
7
 * http://www.e-taxonomy.eu
8
 *
9
 * The contents of this file are subject to the Mozilla Public License Version 1.1
10
 * See http://www.mozilla.org/MPL/MPL-1.1.html for the full license terms.
11
 */
12

    
13
function media_content_type_dir($media_representation, $default = false){
14

    
15
	if($media_representation->mimeType){
16
		return substr($media_representation->mimeType, 0, stripos($media_representation->mimeType, '/'));
17
	} else {
18
		return $default;
19
	}
20
}
21

    
22
function getimagesize_remote($image_url) {
23

    
24
	$contents = cdm_http_request($image_url);
25
	if(!$contents){
26
		return false;
27
	}
28

    
29
	$im = @ImageCreateFromString($contents); // using@ to avoid php user warnings
30
	if (!$im) {
31
		return false;
32
	}
33
	$gis[0] = ImageSX($im);
34
	$gis[1] = ImageSY($im);
35
	// array member 3 is used below to keep with current getimagesize standards
36
	$gis[3] = "width={$gis[0]} height={$gis[1]}";
37
	ImageDestroy($im);
38
	return $gis;
39
}
40

    
41

    
42

    
43
function theme_cdm_media($descriptionElement, $mimeTypePreference){
44
	$out = "";
45

    
46
	_add_js_thickbox();
47

    
48
	$uuid = $descriptionElement->uuid;
49
	$feature = $descriptionElement->feature;
50
	$medias = $descriptionElement->media;
51

    
52
	foreach($medias as $media){
53
		$prefRepresentations = cdm_preferred_media_representations($media, $mimeTypePreference, 300, 400);
54
		$mediaRepresentation = array_shift($prefRepresentations);
55
		if($mediaRepresentation) {
56

    
57
			$contentTypeDirectory = media_content_type_dir($mediaRepresentation);
58

    
59
			$out .= theme('cdm_media_mime_' . $contentTypeDirectory,  $mediaRepresentation, $feature);
60

    
61
			//			$attributes = array('class'=>'thickbox', 'rel'=>'descriptionElement-'.$uuid, 'title'=>$feature->term);
62
			//		    for($i = 0; $part = $mediaRepresentation->representationParts[$i]; $i++){
63
			//		    	if($i == 0){
64
			//		    	    $image_url = drupal_get_path('module', 'cdm_dataportal').'/images/'.$feature->term.'-media.png';
65
			//		    	    $media = '<img src="'.$image_url.'" height="14px" alt="'.$feature->term.'" />';
66
			//		    	    $out .= l($media, $part->uri, $attributes, NULL, NULL, TRUE, TRUE);
67
			//		    	} else {
68
			//		    		$out .= l('', $part->uri, $attributes, NULL, NULL, TRUE);
69
			//		    	}
70
			//		  	}
71
		} else {
72
			// no media available, so display just the type term
73
			$out .=  $feature->representation_L10n;
74
		}
75
	}
76
	return $out;
77

    
78
}
79

    
80
function theme_cdm_mediaTypeTerm($feature, $mediaUrl = false){
81

    
82
	$provider = '';
83
	//TODO directly use favicon from referred URI and overlay on $icon_image, but for now we comment this out
84
	//	if(strpos($mediaUrl, 'biodiversitylibrary.org') > 0){
85
	//    $provider = '-BHL';
86
	//	}
87

    
88
	$icon_image = $feature->representation_L10n.'-media'.$provider.'.png';
89
	$icon_url = drupal_get_path('module', 'cdm_dataportal').'/images/'.$icon_image;
90
	return '<img src="'.$icon_url.'" height="14px" alt="'.$feature->representation_L10n.'" />';
91
}
92

    
93
function theme_cdm_media_mime_application($mediaRepresentation, $feature){
94

    
95
	foreach($mediaRepresentation->parts as $part){
96
		$attributes = array('title'=> theme('cdm_feature_name', $feature->representation_L10n), 'target'=>'_blank');
97
		//$attributes = array('title'=>$feature->representation_L10n, 'target'=>'_blank');
98
		//$attributes = array('title'=>'original publication', 'target'=>'_blank');
99
		$out .= l(theme('cdm_mediaTypeTerm', $feature, $part->uri), $part->uri, $attributes, NULL, NULL, TRUE, TRUE);
100
	}
101
	return $out;
102
}
103

    
104
function theme_cdm_media_mime_image($mediaRepresentation, $feature){
105
	$out = '';
106
	//TODO thickbox is not used anymore -> delete ?
107
	$attributes = array('class'=>'thickbox', 'rel'=>'representation-'.$representation->uuid, 'title'=>$feature->representation_L10n);
108
	for($i = 0; $part = $representation->representationParts[$i]; $i++){
109
		if($i == 0){
110
			$out .= l(theme('cdm_mediaTypeTerm', $feature, $part->uri), $part->uri, $attributes, NULL, NULL, TRUE, TRUE);
111
		} else {
112
			$out .= l('', $part->uri, $attributes, NULL, NULL, TRUE);
113
		}
114
	}
115
	return $out;
116
}
117

    
118
function theme_cdm_media_mime_text($representation, $feature){
119

    
120
	foreach($representation->parts as $part){
121
		$attributes = array('title'=> theme('cdm_feature_name', $feature->representation_L10n), 'target'=>'_blank');
122
		//$attributes = array('title'=>t('original publication'), 'target'=>'_blank');
123
		$out .= l(theme('cdm_mediaTypeTerm', $feature, $part->uri), $part->uri, $attributes, NULL, NULL, TRUE, TRUE);
124
	}
125
	return $out;
126
}
127

    
128

    
129
function theme_cdm_media_caption($media, $elements = array('title', 'description', 'artist', 'location', 'rights'), $fileUri = null){
130

    
131
	$media_metadata = cdm_read_media_metadata($media);
132

    
133
	$out = '<dl class="media-caption">';
134
	//title
135
	if($media_metadata['title'] && (!$elements || array_search('title', $elements)!== false)){
136
		$out .= '<dt class = "title">' . t('Title') . '</dt> <dd class = "title">' . $media_metadata['title'] . '</dd>';
137
		//unset($media_metadata['title']);
138
	}
139
	//description
140
	if($media_metadata['description'] && (!$elements || array_search('description', $elements)!== false)){
141
		$out .= '<dt class = "description">' . t('Description') . '</dt> <dd class = "description">' . $media_metadata['description'] . '</dd>';
142
		//unset($media_metadata['description']);
143
	}
144
	//artist
145
	if($media_metadata['artist'] && (!$elements || array_search('artist', $elements)!== false)){
146
		//$out .= '<span class = "artist">' . ($media_metadata['artist'] ? 'Artist: ' . $media_metadata['artist'] . '</span>' . '<br>' : '');
147
		$out .= '<dt class = "artist">' . t('Artist') . '</dt> <dd class = "astist">' . $media_metadata['artist'] . '</dd>';
148
	}
149
	//location
150
	if(!$elements || array_search('location', $elements)!== false){
151
		$location = '';
152
		$location .= $media_metadata['location']['sublocation'];
153
		if ($location && $media_metadata['location']['city']){
154
			$location .= ', ';
155
		}
156
		$location .= $media_metadata['location']['city'];
157
		if ($location && $media_metadata['location']['province']){
158
			$location .= ', ';
159
		}
160
		$location .= $media_metadata['location']['province'];
161
		if ($location && $media_metadata['location']['country']){
162
			$location .= ' (' . $media_metadata['location']['country'] . ')';
163
		} else {
164
			$location .= $media_metadata['location']['country'];
165
		}
166
		if ($location){
167
			$out .= '<dt class = "location">' . t('Location') . '</dt> <dd class = "location">' . $location  . '</dd>';
168
		}
169
	}
170
	//rights
171
	if(!$elements || array_search('rights', $elements)!== false){
172
		$rights = '';
173
		//copyrights
174
		$cnt = count($media_metadata['rights']['copyright']['agentNames']);
175
		if($cnt > 0){
176
			$rights .= '<dt class="rights">&copy;</dt> <dd class="rights"> ';
177
			for($i = 0; $i < $cnt; $i++){
178
				$rights .= $media_metadata['rights']['copyright']['agentNames'][$i];
179
				if($i+1 < $cnt){
180
					$rights .= ' / ';
181
				}
182
			}
183
			$rights .= '</dd>';
184
		}
185
		//license
186
		$cnt = count($media_metadata['rights']['license']['agentNames']);
187
		if($cnt > 0){
188
			$rights .= '<dt class ="license">' . t('License') . '</dt> <dd class = "license">';
189
			for($i = 0; $i < $cnt; $i++){
190
				$rights .= $media_metadata['rights']['license']['agentNames'][$i];
191
				if ($i+1 < $cnt){
192
					$rights .= ' / ';
193
				}
194
			}
195
			$rights .= '</dd>';
196
		}
197
		if($rights){
198
			$out .=  $rights . '</dt>';
199
		}
200
	}
201
	//TODO add all other metadata elemenst generically
202
	$out .= '</dl>';
203
	//return value
204
	return $out;
205
}
206

    
207

    
208
/**
209
 * @param $mediaList an array of Media entities
210
 * @param $maxExtend
211
 * @param $cols
212
 * @param $maxRows
213
 * @param $captionElements an array possible values are like in the following example: array('title', 'description', 'file', 'filename'),
214
 *         to add a link to the caption: array('titlecache', '#uri'=>t('open Image'));
215
 * @param $mediaLinkType valid values:
216
 *      "NONE": do not link the images,
217
 *      "LIGHTBOX": open the link in a light box,
218
 *      "NORMAL": link to the image page or to the $alternativeMediaUri if it is defined
219
 * @param $alternativeMediaUri an array of alternative URIs to link the images wich will overwrite the URIs of the media parts.
220
 *     The order of URI in this array must correspond with the order of images in $mediaList
221
 * @param $galleryLinkUri an URI to link the the hint on more images to; if null no link is created
222
 * @return unknown_type
223
 */
224
function theme_cdm_media_gallerie(
225
	$mediaList,
226
    $galleryName,
227
	$maxExtend = 150, 
228
	$cols = 4, 
229
	$maxRows = false, 
230
	$captionElements = array('title'),
231
	$mediaLinkType = 'LIGHTBOX', 
232
	$alternativeMediaUri = null, 
233
	$galleryLinkUri = null,
234
	$showCaption = true){
235

    
236
	if(!is_array($captionElements)){
237
		$captionElements = array();
238
	}
239
	//TODO correctly handle multiple media representation parts
240
	$_SESSION['cdm']['last_gallery']= substr($_SERVER['REQUEST_URI'],strpos($_SERVER['REQUEST_URI'], "?q=")+3);
241
	// prevent from errors
242
	if(!isset($mediaList[0])){
243
		return;
244
	}
245

    
246
	$galleryID = "media_gallery_".$galleryName;
247
	$mediaPartLinkAttributes = array();
248
	$openMediaLinkAttributes = array();
249

    
250
	// prepare media links
251
	$doLink = false;
252
	if($mediaLinkType != 'NONE'){
253
		$doLink = true;
254
	}
255
	if($mediaLinkType == 'LIGHTBOX'){
256
		$doLink = true;
257
		_add_js_lightbox($galleryID);
258
	}
259

    
260
	// render the media gallery grid
261
	$out = '<table id="'.$galleryID.'" class="media_gallery">';
262
	$out .= '<colgroup>';
263

    
264
	for($c = 0; $c < $cols; $c++){
265
		$out .= '<col width="'.(100 / $cols).'%">';
266
	}
267
	$out .= '</colgroup>';
268

    
269
	for($r = 0; ($r < $maxRows || !$maxRows) && count($mediaList) > 0; $r++){
270
		$captionParts = array();
271
		$out .= '<tr>';
272
		for($c = 0; $c < $cols; $c++){
273
			$media = array_shift($mediaList);
274
			if(isset($media->representations[0]->parts[0])){
275

    
276
				//
277
				// find preferred representation
278
				//
279
				$preferred_media_representations_list = cdm_preferred_media_representations(
280
				$media,
281
				array('image/jpg', 'image/jpeg', 'image/png', 'image/gif'),
282
				$maxExtend, $maxExtend);
283
				if(count($preferred_media_representations_list) == 0){
284
					// fallback to using the first one in the list
285
					$preferred_media_representations_list = $media->representations;
286
				}
287
				$preferred_media_representation = array_shift($preferred_media_representations_list);
288

    
289
				// $preferred_media_representation->parts[0]->uri = "http://127.0.0.1/images/palmae/palm_tc_14415_1.jpg";
290
				$contentTypeDirectory = media_content_type_dir($preferred_media_representation, 'application');
291
				$mediaIndex++;
292
				$mediaPartHtml = theme('cdm_media_gallerie_'.$contentTypeDirectory, $preferred_media_representation->parts[0], $maxExtend, TRUE);
293
				// --- compose Media Link
294
				$mediaLinkUri = false;
295
				if($alternativeMediaUri){
296
					if(isset($alternativeMediaUri[$mediaIndex])){
297
						$mediaLinkUri = $alternativeMediaUri[$mediaIndex];
298
					}
299
					if(is_string($alternativeMediaUri)){
300
						$mediaLinkUri = $alternativeMediaUri;
301
					}
302
				} else {
303
					$mediaLinkUri = $preferred_media_representation->parts[0]->uri;
304
				}
305

    
306
				_add_js_ahah();
307
				$content_url = cdm_compose_url(CDM_WS_PORTAL_MEDIA, $media->uuid);
308
				
309
				$cdm_proxy_url = url('cdm_api/proxy/'.urlencode($content_url)."/cdm_media_caption/".serialize($captionElements));
310
				$captionPartHtml = '<div class="ahah-content" rel="'.$cdm_proxy_url.'"><span class="loading" style="display: none;">Loading ....</span></div>';
311

    
312
				// generate gallery caption
313
				if($mediaLinkType == 'LIGHTBOX' && $contentTypeDirectory == 'image'){
314
					$mediaPartLinkAttributes['class'] = "lightbox";
315
				} else {
316
					$mediaPartLinkAttributes['target'] = "specimen";
317
					$openMediaLinkAttributes['target'] = "specimen";
318
				}
319
				// generate & add caption to lightbox
320
				$lightBoxCaptionElements = null;
321
				$cdm_proxy_url = url('cdm_api/proxy/'.urlencode($content_url)."/cdm_media_caption"); //.($lightBoxCaptionElements?'/'.join	(',',$lightBoxCaptionElements):''));
322
				$mediaPartLinkAttributes['alt'] = '<div class="ahah-content" rel="'.$cdm_proxy_url.'"><span class="loading" style="display: none;">Loading ....</span></div>';
323

    
324
				if(isset($captionElements['#uri'])){
325
					if($contentTypeDirectory == 'image'){
326
						$captionPartHtml .= '<div>'.l($captionElements['#uri'], path_to_media($media->uuid), null, null, null, FALSE, TRUE).'</div>';
327
					} else {
328
						$captionPartHtml .= '<div>'.l($captionElements['#uri'], $mediaLinkUri, $openMediaLinkAttributes, null, null, TRUE, TRUE).'</div>';
329
					}
330
				}
331
				$captionParts[] = $captionPartHtml;
332

    
333
				// --- surround imagePart with link
334
				if($doLink){
335
					$mediaPartHtml = l($mediaPartHtml, $mediaLinkUri, $mediaPartLinkAttributes, null, null, FALSE, TRUE);
336
				}
337

    
338
			} else {
339
				$mediaPartHtml = '';
340
				$captionParts[] = '';
341
			}
342
			$out .= '<td>'.$mediaPartHtml.'</td>';
343
		}
344
		$out .= '</tr>'; // end of media parts
345
		if ($showCaption){
346
		     if(count($captionElements) > 0){
347
            $out .= '<tr>';
348
            // add caption row
349
            foreach($captionParts as $captionPartHtml){
350
                $out .= '<td>'.$captionPartHtml.'</td>';
351
            }
352
            $out .= '</tr>';
353
            }
354
		}
355
	}
356
	if($galleryLinkUri){
357
		if(count($mediaList) > 0){
358
			$moreHtml = count($mediaList).' '.t('more in gallery');
359
		} else {
360
			$moreHtml = t('open gallery');
361
		}
362
		$moreHtml = l($moreHtml, $galleryLinkUri);
363
		$out .= '<tr><td colspan="'.$cols.'">'.$moreHtml.'</td></tr>';
364
	}
365
	$out .= '</table>';
366
	return $out;
367
}
368

    
369
function theme_cdm_media_gallerie_image($mediaRepresentationPart, $maxExtend, $addPassePartout = FALSE, $attributes = null){
370
	//TODO merge with theme_cdm_media_mime_image?
371

    
372
	if(isset($mediaRepresentationPart)){
373

    
374
		$h = $mediaRepresentationPart->height;
375
		$w = $mediaRepresentationPart->width;
376
		if($w == 0 || $h == 0){
377
			$image_uri = str_replace(' ','%20',$mediaRepresentationPart->uri); //take url and replace spaces
378
			$imageDimensions = getimagesize_remote($image_uri);
379
			if(!$imageDimensions){
380
				return '<div>'.t('Image unavailable, uri: ').$mediaRepresentationPart->uri.'</div>';
381
			}
382
			$w = $imageDimensions[0];
383
			$h = $imageDimensions[1];
384
		}
385
		$margins = '0 0 0 0';
386
		$ratio = $w / $h;
387
		if($ratio > 1){
388
			$displayHeight = round($maxExtend / $ratio);
389
			$displayWidth = $maxExtend;
390
			$m = round(($maxExtend - $displayHeight) / 2);
391
			$margins = 'margin:'.$m.'px 0 '.$m.'px 0;';
392
		} else {
393
			$displayHeight = $maxExtend;
394
			$displayWidth = round($maxExtend * $ratio);
395
			$m = round(($maxExtend - $displayWidth) / 2);
396
			$margins = 'margin:0 '.$m.'px 0 '.$m.'px;';
397
		}
398

    
399
		// turn attributes array into string
400
		$attrStr = ' ';
401
		//$attributes['title'] = 'h:'.$h.', w:'.$w.',ratio:'.$ratio;
402
		if(is_array($attributes)){
403
			foreach($attributes as $name=>$value){
404
				$attrStr .= $name.'="'.$value.'" ';
405
			}
406
		}
407

    
408
		//return  '<img src="'."http://wp5.e-taxonomy.eu/dataportal/cichorieae/media/photos/Lapsana_communis_A_01.jpg".'" width="'.$maxExtend.'" height="'.$maxExtend.'" />';
409
		if($addPassePartout){
410
			$out .= '<div class="image-passe-partout" style="width:'.$maxExtend.'px; height:'.$maxExtend.'px;">';
411
		} else {
412
			// do not add margins if no pass partout is shown
413
			$margins = '';
414
		}
415
		$out .= '<img src="'.$mediaRepresentationPart->uri.'" width="'.$displayWidth.'" height="'.$displayHeight.'" style="'.$margins.'"'.$attrStr.' />';
416

    
417
		if($addPassePartout){
418
			$out .= '</div>';
419
		}
420
		return $out;
421
	}
422

    
423
}
424

    
425
function theme_cdm_media_gallerie_application($mediaRepresentationPart, $maxExtend, $addPassePartout = FALSE, $attributes = null){
426

    
427
	if(isset($mediaRepresentationPart)){
428

    
429
		if($addPassePartout){
430
			$out .= '<div class="image-passe-partout" style="width:'.$maxExtend.'px; height:'.$maxExtend.'px;">';
431
		} else {
432
			// do not add margins if no pass partout is shown
433
			$margins = '';
434
		}
435
		$out .= '<div class="appication">Web Application</div>';
436

    
437
		if($addPassePartout){
438
			$out .= '</div>';
439
		}
440
		return $out;
441
	}
442

    
443
}
444

    
445
function theme_cdm_media_gallerie_text($mediaRepresentationPart, $maxExtend, $addPassePartout = FALSE, $attributes = null){
446

    
447
	if(isset($mediaRepresentationPart)){
448

    
449
		if($addPassePartout){
450
			$out .= '<div class="image-passe-partout" style="width:'.$maxExtend.'px; height:'.$maxExtend.'px;">';
451
		} else {
452
			// do not add margins if no pass partout is shown
453
			$margins = '';
454
		}
455
		$out .= '<div class="appication">Web Application</div>';
456

    
457
		if($addPassePartout){
458
			$out .= '</div>';
459
		}
460
		return $out;
461
	}
462

    
463
}
464

    
465
function theme_cdm_openlayers_image($mediaRepresentationPart, $maxExtend){
466

    
467
	// see http://trac.openlayers.org/wiki/UsingCustomTiles#UsingTilesWithoutaProjection
468
	// and http://trac.openlayers.org/wiki/SettingZoomLevels
469

    
470
	drupal_add_js(drupal_get_path('module', 'cdm_dataportal').'/js/OpenLayers/OpenLayers.js', 'core', 'header');
471

    
472
	//TODO megre code below with code from theme_cdm_media_gallerie_image
473
	//var_dump("MEDIA URI: " . $mediaRepresentationPart->uri);
474
	//TODO merge code below with code from theme_cdm_media_gallerie_image
475
	$w = $mediaRepresentationPart->width;
476
	$h = $mediaRepresentationPart->height;
477

    
478
	if($w == 0 || $h == 0){
479
		$image_uri = str_replace(' ','%20',$mediaRepresentationPart->uri); //take url and replace spaces
480
		$imageDimensions = getimagesize_remote($image_uri);
481
		if(!$imageDimensions){
482
			return '<div>'.t('Image unavailable, uri:').$mediaRepresentationPart->uri.'</div>';
483
		}
484
		$w = $imageDimensions[0];
485
		$h = $imageDimensions[1];
486
	}
487

    
488
	// calculate  maxResolution (default is 360 deg / 256 px) and the bounds
489
	if($w > $h){
490
		$lat = 90;
491
		$lon = 90 * ($h / $w);
492
		$maxRes = $w / $maxExtend;
493
	} else {
494
		$lat = 90 * ($w / $h);
495
		$lon = 90;
496
		$maxRes =  $h / $maxExtend ;
497
	}
498

    
499
	$maxRes *= 1;
500
	drupal_add_js('
501
 var map;
502

    
503
 var imageLayerOptions={
504
     maxResolution: '.$maxRes.',
505
     maxExtent: new OpenLayers.Bounds(0, 0, '.$w.', '.$h.')
506
  };
507
  var mapOptions={
508
      controls:
509
       [
510
         new OpenLayers.Control.PanZoom(),
511
         new OpenLayers.Control.Navigation({zoomWheelEnabled: false, handleRightClicks:true, zoomBoxKeyMask: OpenLayers.Handler.MOD_CTRL})
512
       ],
513
     restrictedExtent:  new OpenLayers.Bounds(0, 0, '.$w.', '.$h.')
514
  };
515

    
516
 var graphic = new OpenLayers.Layer.Image(
517
          \'Image Title\',
518
          \''.$mediaRepresentationPart->uri.'\',
519
          new OpenLayers.Bounds(0, 0, '.$w.', '.$h.'),
520
          new OpenLayers.Size('.$w.', '.$h.'),
521
          imageLayerOptions
522
          );
523

    
524
 function init() {
525
   map = new OpenLayers.Map(\'openlayers_image\', mapOptions);
526
   map.addLayers([graphic]);
527
   map.setCenter(new OpenLayers.LonLat(0, 0), 1);
528
   map.zoomToMaxExtent();
529
 }
530

    
531
$(document).ready(function(){
532
  init();
533

    
534
});'
535
	, 'inline');
536
	$out = '<div id="openlayers_image" class="image_viewer" style="width: '.$maxExtend.'px; height:'.($maxExtend).'px"></div>';
537
	return $out;
538

    
539
}
540

    
541

    
542
function theme_cdm_preferredImage($media, $defaultRepresentationPart, $imageMaxExtend, $parameters = ''){
543

    
544
	if(isset($media[0])){
545
		$representationPart = $media[0]->representations[0]->parts[0];
546
		if($parameters){
547
			$representationPart->uri.$parameters;
548
		}
549
	} else {
550
		$representationPart = $defaultRepresentationPart;
551
	}
552

    
553
	//$widthAndHeight = ($imageWidth ? ' width="'.$imageWidth : '').($imageHeight ? '" height="'.$imageHeight : '');
554
	//  $imageUri = $preferredMedia ? $preferredMedia->representations[0]->parts[0]->uri . $parameters : $defaultImage;
555
	$attributes = array('alt'=>($preferredMedia ? $preferredMedia->representations[0]->parts[0]->uri : "no image available"));
556
	$out .= theme('cdm_media_gallerie_image', $representationPart, $imageMaxExtend, false, $attributes);
557
	// $out = '<img class="left" '.$widthAndHeight.' " src="'.$imageUri.'" alt="'.$altText.'" />';
558
	return $out;
559
}
(3-3/8)