@@ -28,68 +28,7 @@ public ImageService(
2828 _cdnEndpoint = configuration [ "Azure:CdnEndpoint" ] ?? string . Empty ;
2929 }
3030
31- public async Task < ImageInfo > UploadImageAsync ( Stream imageStream , string fileName , string ? altText = null , string ? caption = null )
32- {
33- try
34- {
35- // Create container if it doesn't exist
36- var container = _blobServiceClient . GetBlobContainerClient ( _containerName ) ;
37- await container . CreateIfNotExistsAsync ( PublicAccessType . Blob ) ;
38-
39- // Generate a unique ID and path for the image
40- var imageId = Guid . NewGuid ( ) . ToString ( "N" ) ;
41- var blobPath = GenerateBlobPath ( fileName , imageId ) ;
42-
43- // Calculate content hash
44- var contentHash = await CalculateContentHashAsync ( imageStream ) ;
45- imageStream . Position = 0 ;
46-
47- // Get image dimensions and type
48- using var image = await Image . LoadAsync ( imageStream ) ;
49- imageStream . Position = 0 ;
50-
51- var imageInfo = new ImageInfo
52- {
53- FileName = fileName ,
54- ImageId = imageId ,
55- BlobPath = blobPath ,
56- PublicUrl = GetImageUrl ( imageId ) ,
57- AltText = altText ?? fileName ,
58- Caption = caption ,
59- Width = image . Width ,
60- Height = image . Height ,
61- ContentType = GetContentType ( fileName ) ,
62- UploadedAt = DateTime . UtcNow ,
63- ContentHash = contentHash
64- } ;
65-
66- // Upload original
67- var blobClient = container . GetBlobClient ( blobPath ) ;
68- await blobClient . UploadAsync ( imageStream , new BlobUploadOptions
69- {
70- Metadata = new Dictionary < string , string >
71- {
72- [ "ImageId" ] = imageId ,
73- [ "FileName" ] = fileName ,
74- [ "AltText" ] = altText ?? fileName ,
75- [ "Caption" ] = caption ?? string . Empty ,
76- [ "ContentHash" ] = contentHash
77- }
78- } ) ;
79-
80- // Generate and upload thumbnails
81- await GenerateThumbnailsAsync ( container , imageStream , blobPath ) ;
82-
83- return imageInfo ;
84- }
85- catch ( Exception ex )
86- {
87- _logger . LogError ( ex , "Error uploading image {FileName}" , fileName ) ;
88- throw ;
89- }
90- }
91-
92- public async Task < ImageInfo ? > GetImageAsync ( string imageId )
31+ public async Task < Shared . ImageInfo ? > GetImageAsync ( string imageId )
9332 {
9433 try
9534 {
@@ -103,7 +42,7 @@ public async Task<ImageInfo> UploadImageAsync(Stream imageStream, string fileNam
10342 var blobClient = container . GetBlobClient ( blob . Name ) ;
10443 var properties = await blobClient . GetPropertiesAsync ( ) ;
10544
106- return new ImageInfo
45+ return new Shared . ImageInfo
10746 {
10847 ImageId = imageId ,
10948 FileName = properties . Value . Metadata [ "FileName" ] ,
@@ -127,52 +66,7 @@ public async Task<ImageInfo> UploadImageAsync(Stream imageStream, string fileNam
12766 }
12867 }
12968
130- public async Task DeleteImageAsync ( string imageId )
131- {
132- try
133- {
134- var container = _blobServiceClient . GetBlobContainerClient ( _containerName ) ;
135- var blobs = container . GetBlobsAsync ( prefix : $ "{ imageId } /") ;
136-
137- await foreach ( var blob in blobs )
138- {
139- await container . DeleteBlobAsync ( blob . Name ) ;
140- }
141- }
142- catch ( Exception ex )
143- {
144- _logger . LogError ( ex , "Error deleting image {ImageId}" , imageId ) ;
145- throw ;
146- }
147- }
148-
149- public async Task UpdateImageMetadataAsync ( string imageId , string ? altText = null , string ? caption = null )
150- {
151- try
152- {
153- var container = _blobServiceClient . GetBlobContainerClient ( _containerName ) ;
154- var blobs = container . GetBlobsAsync ( prefix : $ "{ imageId } /") ;
155-
156- await foreach ( var blob in blobs )
157- {
158- var blobClient = container . GetBlobClient ( blob . Name ) ;
159- var properties = await blobClient . GetPropertiesAsync ( ) ;
160- var metadata = new Dictionary < string , string > ( properties . Value . Metadata ) ;
161-
162- if ( altText != null ) metadata [ "AltText" ] = altText ;
163- if ( caption != null ) metadata [ "Caption" ] = caption ;
164-
165- await blobClient . SetMetadataAsync ( metadata ) ;
166- }
167- }
168- catch ( Exception ex )
169- {
170- _logger . LogError ( ex , "Error updating image metadata {ImageId}" , imageId ) ;
171- throw ;
172- }
173- }
174-
175- public string GetImageUrl ( string imageId , ImageSize size = ImageSize . Original )
69+ public string GetImageUrl ( string imageId , ImageSize size = ImageSize . Original )
17670 {
17771 var sizeFolder = size switch
17872 {
@@ -190,64 +84,6 @@ public string GetImageUrl(string imageId, ImageSize size = ImageSize.Original)
19084 return $ "{ _blobServiceClient . Uri } { _containerName } /{ imageId } /{ sizeFolder } ";
19185 }
19286
193- private async Task GenerateThumbnailsAsync ( BlobContainerClient container , Stream originalStream , string originalPath )
194- {
195- originalStream . Position = 0 ;
196- using var image = await Image . LoadAsync ( originalStream ) ;
197-
198- // Define thumbnail sizes
199- var sizes = new Dictionary < string , ( int width , int height ) >
200- {
201- [ "thumbnail" ] = ( 150 , 150 ) ,
202- [ "medium" ] = ( 400 , 400 ) ,
203- [ "large" ] = ( 800 , 800 )
204- } ;
205-
206- foreach ( var size in sizes )
207- {
208- var resized = image . Clone ( ctx => ctx . Resize ( new ResizeOptions
209- {
210- Mode = ResizeMode . Max ,
211- Size = new Size ( size . Value . width , size . Value . height )
212- } ) ) ;
213-
214- var thumbnailPath = originalPath . Replace ( "/original" , $ "/{ size . Key } ") ;
215- var thumbnailBlob = container . GetBlobClient ( thumbnailPath ) ;
216-
217- using var ms = new MemoryStream ( ) ;
218- await resized . SaveAsync ( ms , image . Metadata . DecodedImageFormat ) ;
219- ms . Position = 0 ;
220-
221- await thumbnailBlob . UploadAsync ( ms , overwrite : true ) ;
222- }
223- }
224-
225- private string GenerateBlobPath ( string fileName , string imageId )
226- {
227- var extension = Path . GetExtension ( fileName ) ;
228- return $ "{ imageId } /original{ extension } ";
229- }
230-
231- private async Task < string > CalculateContentHashAsync ( Stream stream )
232- {
233- using var sha256 = SHA256 . Create ( ) ;
234- var hash = await sha256 . ComputeHashAsync ( stream ) ;
235- return Convert . ToBase64String ( hash ) ;
236- }
237-
238- private string GetContentType ( string fileName )
239- {
240- var extension = Path . GetExtension ( fileName ) . ToLowerInvariant ( ) ;
241- return extension switch
242- {
243- ".jpg" or ".jpeg" => "image/jpeg" ,
244- ".png" => "image/png" ,
245- ".gif" => "image/gif" ,
246- ".webp" => "image/webp" ,
247- _ => "application/octet-stream"
248- } ;
249- }
250-
25187 public string ? GetImageIdByFilename ( string filename )
25288 {
25389 try
0 commit comments