Use case: Get thumbnail download URL for an annotation
Before you start
Before you download a thumbnail for an annotation, ensure you have completed the following prerequisites:
- Thumbnail Exists: The annotation must have a thumbnail already uploaded (check
HasThumbnailproperty). - Project Access: Ensure you have the necessary permissions to read annotations in the target project.
- Set Up SDK Environment: Confirm that your Unity environment is correctly configured with the Collaboration SDK.
- HTTP Client Ready: Prepare your HTTP client or Unity web request system to download from the URL.
How do I...?
Get a pre-signed URL to download a thumbnail
To obtain a secure download URL for an annotation thumbnail, follow these steps:
- Verify Thumbnail Exists: Check that the annotation has
HasThumbnail = true. - Prepare Identifiers: Ensure you have the correct project and annotation identifiers.
- Request Download URL: Use the SDK to request a pre-signed download URL.
- Download Image: Use the returned URL to download the thumbnail image.
- Display or Process: Display the thumbnail in your UI or process it as needed.
Example:
var projectId = new ProjectId("87cf845f-8ca7-4b2f-9cc1-c3d731335810");
var annotationId = new AnnotationId("a1b2c3d4-e5f6-7890-abcd-ef1234567890");
var annotationReference = new annotationReference(projectId, annotationId);
// Get the pre-signed download URL
ReadThumbnailDownloadUrlResult result = await annotationManagement.ReadThumbnailDownloadUrlAsync(
annotationReference,
cancellationToken);
string downloadUrl = result.Url;
Debug.Log($"Thumbnail download URL: {downloadUrl}");
// Download the thumbnail (see examples below)
Download and display thumbnail in Unity
Here's a complete example showing how to download and display a thumbnail as a Unity Texture2D:
public async Task<Texture2D> DownloadAndDisplayThumbnail(
ProjectId projectId,
AnnotationId annotationId)
{
var annotationReference = new annotationReference(projectId, annotationId);
try
{
// Step 1: Get the download URL
ReadThumbnailDownloadUrlResult urlResult = await annotationManagement.ReadThumbnailDownloadUrlAsync(
annotationReference,
cancellationToken);
Debug.Log($"Obtained download URL: {urlResult.Url}");
// Step 2: Download the image
using (UnityWebRequest webRequest = UnityWebRequestTexture.GetTexture(urlResult.Url))
{
await webRequest.SendWebRequest();
if (webRequest.result != UnityWebRequest.Result.Success)
{
Debug.LogError($"Failed to download thumbnail: {webRequest.error}");
return null;
}
// Step 3: Get the texture from the request
Texture2D thumbnail = DownloadHandlerTexture.GetContent(webRequest);
Debug.Log($"Thumbnail downloaded: {thumbnail.width}x{thumbnail.height}");
return thumbnail;
}
}
catch (Exception ex)
{
Debug.LogError($"Failed to download thumbnail: {ex.Message}");
return null;
}
}
// Usage:
Texture2D thumbnail = await DownloadAndDisplayThumbnail(projectId, annotationId);
if (thumbnail != null)
{
// Display in UI
thumbnailImage.texture = thumbnail;
}
Check if thumbnail exists before downloading
Always verify that a thumbnail exists before attempting to download:
public async Task<Texture2D> DownloadThumbnailIfExists(
ProjectId projectId,
AnnotationId annotationId)
{
var annotationReference = new annotationReference(projectId, annotationId);
// First, read the annotation to check if it has a thumbnail
var annotationResult = await annotationManagement.ReadAnnotationAsync(
annotationReference,
cancellationToken: cancellationToken);
if (!annotationResult.Annotation.HasThumbnail)
{
Debug.Log("Annotation does not have a thumbnail");
return null;
}
// Thumbnail exists, proceed with download
return await DownloadAndDisplayThumbnail(projectId, annotationId);
}
Download thumbnail with caching
To avoid re-downloading thumbnails, implement caching:
private Dictionary<string, Texture2D> thumbnailCache = new Dictionary<string, Texture2D>();
public async Task<Texture2D> GetThumbnailWithCache(
ProjectId projectId,
AnnotationId annotationId)
{
string cacheKey = $"{projectId}_{annotationId}";
// Check cache first
if (thumbnailCache.TryGetValue(cacheKey, out Texture2D cachedThumbnail))
{
Debug.Log("Returning cached thumbnail");
return cachedThumbnail;
}
// Download if not in cache
Texture2D thumbnail = await DownloadAndDisplayThumbnail(projectId, annotationId);
if (thumbnail != null)
{
thumbnailCache[cacheKey] = thumbnail;
Debug.Log("Thumbnail cached");
}
return thumbnail;
}
public void ClearThumbnailCache()
{
foreach (var texture in thumbnailCache.Values)
{
if (texture != null)
{
Destroy(texture);
}
}
thumbnailCache.Clear();
}
Download multiple thumbnails efficiently
To download thumbnails for multiple annotations in parallel:
public async Task<Dictionary<AnnotationId, Texture2D>> DownloadMultipleThumbnails(
ProjectId projectId,
List<AnnotationId> annotationIds)
{
var results = new Dictionary<AnnotationId, Texture2D>();
// Create download tasks for all annotations
var downloadTasks = annotationIds.Select(async annotationId =>
{
try
{
var thumbnail = await DownloadAndDisplayThumbnail(projectId, annotationId);
return (annotationId, thumbnail);
}
catch (Exception ex)
{
Debug.LogWarning($"Failed to download thumbnail for {annotationId}: {ex.Message}");
return (annotationId, (Texture2D)null);
}
});
// Wait for all downloads to complete
var downloadResults = await Task.WhenAll(downloadTasks);
// Build results dictionary
foreach (var (annotationId, thumbnail) in downloadResults)
{
if (thumbnail != null)
{
results[annotationId] = thumbnail;
}
}
Debug.Log($"Downloaded {results.Count} thumbnails out of {annotationIds.Count}");
return results;
}
Download thumbnail as byte array
If you need the raw image data instead of a Texture2D:
public async Task<byte[]> DownloadThumbnailAsBytes(
ProjectId projectId,
AnnotationId annotationId)
{
try
{
var annotationReference = new annotationReference(projectId, annotationId);
// Get download URL
ReadThumbnailDownloadUrlResult urlResult = await annotationManagement.ReadThumbnailDownloadUrlAsync(
annotationReference,
cancellationToken);
// Download as bytes using HttpClient
using (var httpClient = new HttpClient())
{
byte[] imageData = await httpClient.GetByteArrayAsync(urlResult.Url);
Debug.Log($"Downloaded {imageData.Length} bytes");
return imageData;
}
}
catch (Exception ex)
{
Debug.LogError($"Failed to download thumbnail: {ex.Message}");
return null;
}
}
Handle download failures gracefully
To provide fallback behavior when thumbnail download fails:
public async Task<Texture2D> DownloadThumbnailWithFallback(
ProjectId projectId,
AnnotationId annotationId,
Texture2D fallbackTexture)
{
try
{
var thumbnail = await DownloadAndDisplayThumbnail(projectId, annotationId);
return thumbnail ?? fallbackTexture;
}
catch (Exception ex)
{
Debug.LogWarning($"Thumbnail download failed, using fallback: {ex.Message}");
return fallbackTexture;
}
}
// Usage with placeholder image:
Texture2D placeholderImage = Resources.Load<Texture2D>("PlaceholderThumbnail");
Texture2D thumbnail = await DownloadThumbnailWithFallback(
projectId,
annotationId,
placeholderImage);
Understanding pre-signed download URLs
Pre-signed download URLs provide secure, temporary access to cloud storage:
- Time-Limited: The URL expires after a certain period (typically minutes to hours)
- Direct Download: Your application downloads directly from cloud storage, not through Unity servers
- Secure: The URL includes authentication tokens, so no additional credentials are needed
- GET Request: Use HTTP GET method to download from the pre-signed URL
- No Authentication Headers: The URL is self-authenticated; don't add additional auth headers
Best practices
- Check HasThumbnail First: Always verify the annotation has a thumbnail before requesting download URL
- Cache Thumbnails: Store downloaded thumbnails in memory or on disk to avoid redundant downloads
- Handle Expiration: If download fails, request a new URL rather than retrying with the expired URL
- Use Appropriate Size: Consider thumbnail dimensions for your UI needs
- Cleanup: Remember to destroy Texture2D objects when no longer needed to prevent memory leaks
- Error Handling: Provide fallback images or placeholder graphics when downloads fail
- Parallel Downloads: Use Task.WhenAll for downloading multiple thumbnails efficiently
Common use cases
- Annotation Lists: Display thumbnail previews in annotation list views
- Detail Views: Show full thumbnail when user opens an annotation
- Export/Reports: Include thumbnails in exported reports or documentation
- Notifications: Show thumbnail previews in notification systems
- Search Results: Display thumbnails in search result views
For related operations, see documentation on uploading thumbnails and finalizing uploads.
See the API documentation for more details on the ReadThumbnailDownloadUrlAsync method.