Skip to content

Commit bbfc80d

Browse files
committed
Add viewing thermal reference images
1 parent 349133f commit bbfc80d

8 files changed

Lines changed: 1091 additions & 4 deletions

File tree

api/.env.example

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# Azure storage account name for thermal reference images
2+
Storage__ThermalReferenceStorageAccount=<your-storage-account-name>

api/Controllers/ThermalReferenceMetadataController.cs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ namespace api.Controllers;
1111
public class ThermalReferenceMetadataController(
1212
ILogger<ThermalReferenceMetadataController> logger,
1313
IThermalReferenceMetadataService thermalReferenceMetadataService,
14+
IThermalImageService thermalImageService,
1415
IConfiguration configuration
1516
) : ControllerBase
1617
{
@@ -164,6 +165,41 @@ public async Task<ActionResult> DeleteThermalReferenceMetadata([FromRoute] Guid
164165
}
165166
}
166167

168+
[HttpGet("id/{id}/image")]
169+
[Authorize(Roles = Role.Any)]
170+
[ProducesResponseType(typeof(FileContentResult), StatusCodes.Status200OK)]
171+
[ProducesResponseType(StatusCodes.Status404NotFound)]
172+
public async Task<ActionResult> GetThermalReferenceImage([FromRoute] Guid id)
173+
{
174+
try
175+
{
176+
var metadata = await thermalReferenceMetadataService.ReadById(id);
177+
if (metadata is null)
178+
{
179+
return NotFound($"Could not find thermal reference metadata with id {id}");
180+
}
181+
182+
var result = await thermalImageService.GetThermalImageAsJpegAsync(
183+
metadata.ReferenceImageBlobStorageLocation
184+
);
185+
186+
Response.Headers["X-Temperature-Min"] = result.MinTemperature.ToString("F2");
187+
Response.Headers["X-Temperature-Max"] = result.MaxTemperature.ToString("F2");
188+
Response.Headers["Access-Control-Expose-Headers"] =
189+
"X-Temperature-Min, X-Temperature-Max";
190+
191+
return File(result.JpegBytes, "image/jpeg");
192+
}
193+
catch (Exception ex)
194+
{
195+
logger.LogError(ex, "Error generating thermal reference image for id {Id}", id);
196+
return StatusCode(
197+
StatusCodes.Status500InternalServerError,
198+
"An error occurred while generating the thermal reference image"
199+
);
200+
}
201+
}
202+
167203
private (
168204
BlobStorageLocation imageLocation,
169205
BlobStorageLocation polygonLocation

api/Program.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@
7070
);
7171

7272
builder.Services.AddScoped<IThermalReferenceMetadataService, ThermalReferenceMetadataService>();
73+
builder.Services.AddScoped<IBlobStorageService, BlobStorageService>();
74+
builder.Services.AddScoped<IThermalImageService, ThermalImageService>();
7375
builder.Services.AddScoped<IInspectionRecordService, InspectionRecordService>();
7476
builder.Services.AddScoped<IAnalysisService, AnalysisService>();
7577
builder.Services.AddScoped<IAnalysisGroupService, AnalysisGroupService>();

api/Services/BlobStorageService.cs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
using api.Database.Models;
2+
using Azure.Core;
3+
using Azure.Storage.Blobs;
4+
5+
namespace api.Services;
6+
7+
public interface IBlobStorageService
8+
{
9+
Task<MemoryStream> DownloadBlobAsync(BlobStorageLocation location);
10+
}
11+
12+
public class BlobStorageService(TokenCredential credential) : IBlobStorageService
13+
{
14+
public async Task<MemoryStream> DownloadBlobAsync(BlobStorageLocation location)
15+
{
16+
if (string.IsNullOrWhiteSpace(location.StorageAccount))
17+
throw new InvalidOperationException("BlobStorageLocation.StorageAccount is empty.");
18+
19+
if (string.IsNullOrWhiteSpace(location.BlobContainer))
20+
throw new InvalidOperationException(
21+
$"BlobStorageLocation.BlobContainer is empty for storage account '{location.StorageAccount}'."
22+
);
23+
24+
if (string.IsNullOrWhiteSpace(location.BlobName))
25+
throw new InvalidOperationException(
26+
$"BlobStorageLocation.BlobName is empty for storage account '{location.StorageAccount}/{location.BlobContainer}'."
27+
);
28+
29+
var serviceClient = new BlobServiceClient(
30+
new Uri($"https://{location.StorageAccount}.blob.core.windows.net"),
31+
credential
32+
);
33+
34+
var containerClient = serviceClient.GetBlobContainerClient(location.BlobContainer);
35+
var blobClient = containerClient.GetBlobClient(location.BlobName);
36+
37+
var stream = new MemoryStream();
38+
await blobClient.DownloadToAsync(stream);
39+
stream.Position = 0;
40+
return stream;
41+
}
42+
}

0 commit comments

Comments
 (0)