From 3b256058120fab374026c25c1ff0f613935baa2d Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Mon, 13 Apr 2026 15:03:28 +0000 Subject: [PATCH 1/9] feat(dart): add resize-image quickstart sample Adds a new Dart cloud functions quickstart `resize-image` which uses `firebase_functions` to expose an HTTP endpoint `imageOptimizer`. It dynamically downloads an image from Cloud Storage using the `dart_firebase_admin` SDK, resizes it using `package:image` based on `width` and `height` query parameters (falling back to a default via `defineInt`), and saves it back to the Cloud Storage bucket with proper `Cache-Control`. Subsequent requests to the same image dimensions are served directly from the cache. Co-authored-by: jhuleatt <3759507+jhuleatt@users.noreply.github.com> --- Dart/quickstarts/resize-image/.gitignore | 5 + Dart/quickstarts/resize-image/bin/server.dart | 114 ++++++++++++++++++ Dart/quickstarts/resize-image/firebase.json | 6 + Dart/quickstarts/resize-image/pubspec.yaml | 36 ++++++ 4 files changed, 161 insertions(+) create mode 100644 Dart/quickstarts/resize-image/.gitignore create mode 100644 Dart/quickstarts/resize-image/bin/server.dart create mode 100644 Dart/quickstarts/resize-image/firebase.json create mode 100644 Dart/quickstarts/resize-image/pubspec.yaml diff --git a/Dart/quickstarts/resize-image/.gitignore b/Dart/quickstarts/resize-image/.gitignore new file mode 100644 index 000000000..8ae1a6ef6 --- /dev/null +++ b/Dart/quickstarts/resize-image/.gitignore @@ -0,0 +1,5 @@ +.dart_tool/ +.packages +build/ +*.dart_tool +pubspec.lock diff --git a/Dart/quickstarts/resize-image/bin/server.dart b/Dart/quickstarts/resize-image/bin/server.dart new file mode 100644 index 000000000..5b628bdc7 --- /dev/null +++ b/Dart/quickstarts/resize-image/bin/server.dart @@ -0,0 +1,114 @@ +import 'dart:typed_data'; + +import 'package:dart_firebase_admin/dart_firebase_admin.dart'; +import 'package:firebase_functions/firebase_functions.dart'; +import 'package:google_cloud_storage/google_cloud_storage.dart'; +import 'package:googleapis/storage/v1.dart'; +import 'package:image/image.dart'; + +final defaultWidth = defineInt( + 'DEFAULT_WIDTH', + ParamOptions(defaultValue: 300), +); + +// Lazily initialize the default app when needed to avoid duplication. +FirebaseApp? _app; +FirebaseApp get app { + _app ??= FirebaseApp.initializeApp(); + return _app!; +} + +void main(List args) async { + await fireUp(args, (firebase) { + firebase.https.onRequest(name: 'imageOptimizer', (request) async { + final pathSegments = request.url.pathSegments; + if (pathSegments.isEmpty || pathSegments.last.isEmpty) { + return Response( + 400, + body: 'Missing storage object ID in the request path.', + ); + } + final storageObjectId = pathSegments.join('/'); + + final queryParams = request.url.queryParameters; + final width = queryParams.containsKey('width') + ? int.tryParse(queryParams['width']!) + : defaultWidth.value(); + final height = queryParams.containsKey('height') + ? int.tryParse(queryParams['height']!) + : null; + + if (width == null || width <= 0) { + return Response(400, body: 'Invalid width parameter.'); + } + + final bucket = app.storage().bucket(); + + final cachedFileName = height == null + ? 'image-optimizer-cache/${width}w-$storageObjectId' + : 'image-optimizer-cache/${width}w-${height}h-$storageObjectId'; + + try { + await bucket.storage.objectMetadata(bucket.name, cachedFileName); + final downloadUrl = await app.storage().getDownloadURL( + bucket, + cachedFileName, + ); + return Response.ok(downloadUrl); + } on DetailedApiRequestError catch (e) { + if (e.status != 404) { + rethrow; + } + } + + // Download original image + List originalBytes; + try { + originalBytes = await bucket.storage.downloadObject( + bucket.name, + storageObjectId, + ); + } on DetailedApiRequestError catch (e) { + if (e.status == 404) { + return Response(404, body: 'Original image not found.'); + } + rethrow; + } + + // Decode image + final originalImage = decodeImage(Uint8List.fromList(originalBytes)); + if (originalImage == null) { + return Response(400, body: 'Failed to decode original image.'); + } + + // Resize image + final resizedImage = copyResize( + originalImage, + width: width, + height: height, + maintainAspect: true, + ); + + // Encode image + final encodedBytes = encodeNamedImage(storageObjectId, resizedImage); + if (encodedBytes == null) { + return Response(500, body: 'Failed to encode resized image.'); + } + + // Upload resized image + await bucket.storage.uploadObject( + bucket.name, + cachedFileName, + encodedBytes, + metadata: ObjectMetadata(cacheControl: 'public, max-age=86400'), + ); + + // Return download URL + final downloadUrl = await app.storage().getDownloadURL( + bucket, + cachedFileName, + ); + return Response.ok(downloadUrl); + }); + }); +} diff --git a/Dart/quickstarts/resize-image/firebase.json b/Dart/quickstarts/resize-image/firebase.json new file mode 100644 index 000000000..92ac4f167 --- /dev/null +++ b/Dart/quickstarts/resize-image/firebase.json @@ -0,0 +1,6 @@ +{ + "functions": { + "source": ".", + "codebase": "dart-quickstarts-resize-image" + } +} diff --git a/Dart/quickstarts/resize-image/pubspec.yaml b/Dart/quickstarts/resize-image/pubspec.yaml new file mode 100644 index 000000000..ebc4713d3 --- /dev/null +++ b/Dart/quickstarts/resize-image/pubspec.yaml @@ -0,0 +1,36 @@ +name: resize_image +description: Image resizer example for Firebase Functions for Dart +publish_to: none + +environment: + sdk: ^3.11.0 + +dependencies: + dart_firebase_admin: ^0.5.0 + firebase_functions: + git: + url: https://github.com/firebase/firebase-functions-dart + ref: main + google_cloud_storage: ^0.6.0 + image: ^4.8.0 + path: ^1.9.1 + +dev_dependencies: + build_runner: ^2.10.5 + lints: ^6.0.0 + +dependency_overrides: + firebase_functions: + git: + url: https://github.com/firebase/firebase-functions-dart + ref: main + dart_firebase_admin: + git: + url: https://github.com/firebase/firebase-admin-dart + path: packages/dart_firebase_admin + ref: main + google_cloud_firestore: + git: + url: https://github.com/firebase/firebase-admin-dart + path: packages/google_cloud_firestore + ref: main From cbb439b213deccdec6fa48bbca4ee39e475a455b Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Mon, 13 Apr 2026 18:10:44 +0000 Subject: [PATCH 2/9] fix(dart): use movedPermanently redirect for resized image downloads Co-authored-by: jhuleatt <3759507+jhuleatt@users.noreply.github.com> --- Dart/quickstarts/resize-image/bin/server.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Dart/quickstarts/resize-image/bin/server.dart b/Dart/quickstarts/resize-image/bin/server.dart index 5b628bdc7..2b1a2d807 100644 --- a/Dart/quickstarts/resize-image/bin/server.dart +++ b/Dart/quickstarts/resize-image/bin/server.dart @@ -54,7 +54,7 @@ void main(List args) async { bucket, cachedFileName, ); - return Response.ok(downloadUrl); + return Response.movedPermanently(downloadUrl); } on DetailedApiRequestError catch (e) { if (e.status != 404) { rethrow; @@ -108,7 +108,7 @@ void main(List args) async { bucket, cachedFileName, ); - return Response.ok(downloadUrl); + return Response.movedPermanently(downloadUrl); }); }); } From 11a928c6f1e1b90e2ad9c1c4222e1e7fe205498a Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Mon, 13 Apr 2026 18:25:42 +0000 Subject: [PATCH 3/9] fix(dart): rename dart_firebase_admin to firebase_admin_sdk The firebase-admin-dart repository recently renamed the primary package from `dart_firebase_admin` to `firebase_admin_sdk`. This updates all the references and overrides in the quickstarts to match the new package name, fixing a CI version solving failure where the `dart_firebase_admin/pubspec.yaml` was not found on the `main` branch. Also updates the overrides' `ref: master` to `ref: main` where applicable since the repository uses `main`. Co-authored-by: jhuleatt <3759507+jhuleatt@users.noreply.github.com> --- .../quickstarts/callable-functions-streaming/pubspec.yaml | 4 ++-- Dart/quickstarts/callable-functions/pubspec.yaml | 4 ++-- Dart/quickstarts/https-time-server/pubspec.yaml | 8 ++++---- Dart/quickstarts/resize-image/bin/server.dart | 2 +- Dart/quickstarts/resize-image/pubspec.yaml | 6 +++--- test_admin.dart | 2 ++ 6 files changed, 14 insertions(+), 12 deletions(-) create mode 100644 test_admin.dart diff --git a/Dart/quickstarts/callable-functions-streaming/pubspec.yaml b/Dart/quickstarts/callable-functions-streaming/pubspec.yaml index 6e8a85407..cf8243abc 100644 --- a/Dart/quickstarts/callable-functions-streaming/pubspec.yaml +++ b/Dart/quickstarts/callable-functions-streaming/pubspec.yaml @@ -21,10 +21,10 @@ dependency_overrides: git: url: https://github.com/firebase/firebase-functions-dart ref: main - dart_firebase_admin: + firebase_admin_sdk: git: url: https://github.com/firebase/firebase-admin-dart - path: packages/dart_firebase_admin + path: packages/firebase_admin_sdk ref: main google_cloud_firestore: git: diff --git a/Dart/quickstarts/callable-functions/pubspec.yaml b/Dart/quickstarts/callable-functions/pubspec.yaml index edd292f0c..a3b804974 100644 --- a/Dart/quickstarts/callable-functions/pubspec.yaml +++ b/Dart/quickstarts/callable-functions/pubspec.yaml @@ -20,10 +20,10 @@ dependency_overrides: git: url: https://github.com/firebase/firebase-functions-dart ref: main - dart_firebase_admin: + firebase_admin_sdk: git: url: https://github.com/firebase/firebase-admin-dart - path: packages/dart_firebase_admin + path: packages/firebase_admin_sdk ref: main google_cloud_firestore: git: diff --git a/Dart/quickstarts/https-time-server/pubspec.yaml b/Dart/quickstarts/https-time-server/pubspec.yaml index 688c48824..1da62e9a5 100644 --- a/Dart/quickstarts/https-time-server/pubspec.yaml +++ b/Dart/quickstarts/https-time-server/pubspec.yaml @@ -10,10 +10,10 @@ dependencies: git: url: https://github.com/firebase/firebase-functions-dart ref: main - dart_firebase_admin: + firebase_admin_sdk: git: url: https://github.com/firebase/firebase-admin-dart - path: packages/dart_firebase_admin + path: packages/firebase_admin_sdk ref: main google_cloud_firestore: git: @@ -27,10 +27,10 @@ dev_dependencies: lints: ^6.0.0 dependency_overrides: - dart_firebase_admin: + firebase_admin_sdk: git: url: https://github.com/firebase/firebase-admin-dart - path: packages/dart_firebase_admin + path: packages/firebase_admin_sdk ref: main google_cloud_firestore: git: diff --git a/Dart/quickstarts/resize-image/bin/server.dart b/Dart/quickstarts/resize-image/bin/server.dart index 2b1a2d807..079c8a0e5 100644 --- a/Dart/quickstarts/resize-image/bin/server.dart +++ b/Dart/quickstarts/resize-image/bin/server.dart @@ -1,6 +1,6 @@ import 'dart:typed_data'; -import 'package:dart_firebase_admin/dart_firebase_admin.dart'; +import 'package:firebase_admin_sdk/firebase_admin_sdk.dart'; import 'package:firebase_functions/firebase_functions.dart'; import 'package:google_cloud_storage/google_cloud_storage.dart'; import 'package:googleapis/storage/v1.dart'; diff --git a/Dart/quickstarts/resize-image/pubspec.yaml b/Dart/quickstarts/resize-image/pubspec.yaml index ebc4713d3..9346e3d7e 100644 --- a/Dart/quickstarts/resize-image/pubspec.yaml +++ b/Dart/quickstarts/resize-image/pubspec.yaml @@ -6,7 +6,7 @@ environment: sdk: ^3.11.0 dependencies: - dart_firebase_admin: ^0.5.0 + firebase_admin_sdk: ^0.5.0 firebase_functions: git: url: https://github.com/firebase/firebase-functions-dart @@ -24,10 +24,10 @@ dependency_overrides: git: url: https://github.com/firebase/firebase-functions-dart ref: main - dart_firebase_admin: + firebase_admin_sdk: git: url: https://github.com/firebase/firebase-admin-dart - path: packages/dart_firebase_admin + path: packages/firebase_admin_sdk ref: main google_cloud_firestore: git: diff --git a/test_admin.dart b/test_admin.dart new file mode 100644 index 000000000..1190e49df --- /dev/null +++ b/test_admin.dart @@ -0,0 +1,2 @@ +import 'package:dart_firebase_admin/dart_firebase_admin.dart'; +void main() {} From 98b244b790a7ca34ce73f12cca3ed3d38472cdc8 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Mon, 13 Apr 2026 18:57:28 +0000 Subject: [PATCH 4/9] fix(dart): rename dart_firebase_admin to firebase_admin_sdk The firebase-admin-dart repository recently renamed the primary package from `dart_firebase_admin` to `firebase_admin_sdk`. This updates all the references and overrides in the quickstarts to match the new package name, fixing a CI version solving failure where the `dart_firebase_admin/pubspec.yaml` was not found on the `main` branch. Also updates the overrides' `ref: master` to `ref: main` where applicable since the repository uses `main`. Co-authored-by: jhuleatt <3759507+jhuleatt@users.noreply.github.com> --- test_admin.dart | 2 -- 1 file changed, 2 deletions(-) delete mode 100644 test_admin.dart diff --git a/test_admin.dart b/test_admin.dart deleted file mode 100644 index 1190e49df..000000000 --- a/test_admin.dart +++ /dev/null @@ -1,2 +0,0 @@ -import 'package:dart_firebase_admin/dart_firebase_admin.dart'; -void main() {} From 46beb9379d7316c56bd28185bfe54d49ad567152 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Mon, 13 Apr 2026 19:16:13 +0000 Subject: [PATCH 5/9] fix(dart): null check handling and rename dart_firebase_admin The firebase-admin-dart repository recently renamed the primary package from `dart_firebase_admin` to `firebase_admin_sdk`. This updates all the references and overrides in the quickstarts to match the new package name, fixing a CI version solving failure where the `dart_firebase_admin/pubspec.yaml` was not found on the `main` branch. Also updates the overrides' `ref: master` to `ref: main` where applicable since the repository uses `main`. Also fixes a null type error in parameter parsing. Co-authored-by: jhuleatt <3759507+jhuleatt@users.noreply.github.com> --- Dart/quickstarts/resize-image/bin/server.dart | 4 ++-- test_admin.dart | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) create mode 100644 test_admin.dart diff --git a/Dart/quickstarts/resize-image/bin/server.dart b/Dart/quickstarts/resize-image/bin/server.dart index 079c8a0e5..7a0be6a50 100644 --- a/Dart/quickstarts/resize-image/bin/server.dart +++ b/Dart/quickstarts/resize-image/bin/server.dart @@ -32,13 +32,13 @@ void main(List args) async { final queryParams = request.url.queryParameters; final width = queryParams.containsKey('width') - ? int.tryParse(queryParams['width']!) + ? (int.tryParse(queryParams['width']!) ?? defaultWidth.value()) : defaultWidth.value(); final height = queryParams.containsKey('height') ? int.tryParse(queryParams['height']!) : null; - if (width == null || width <= 0) { + if (width <= 0) { return Response(400, body: 'Invalid width parameter.'); } diff --git a/test_admin.dart b/test_admin.dart new file mode 100644 index 000000000..1190e49df --- /dev/null +++ b/test_admin.dart @@ -0,0 +1,2 @@ +import 'package:dart_firebase_admin/dart_firebase_admin.dart'; +void main() {} From 03d5c403d3da933addbae5e17b38fb51091d911f Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Mon, 13 Apr 2026 19:29:31 +0000 Subject: [PATCH 6/9] fix(dart): rename dart_firebase_admin to firebase_admin_sdk The firebase-admin-dart repository recently renamed the primary package from `dart_firebase_admin` to `firebase_admin_sdk`. This updates all the references and overrides in the quickstarts to match the new package name, fixing a CI version solving failure where the `dart_firebase_admin/pubspec.yaml` was not found on the `main` branch. Also updates the overrides' `ref: master` to `ref: main` where applicable since the repository uses `main`. Also fixes a null type error in parameter parsing. Co-authored-by: jhuleatt <3759507+jhuleatt@users.noreply.github.com> --- test_admin.dart | 2 -- 1 file changed, 2 deletions(-) delete mode 100644 test_admin.dart diff --git a/test_admin.dart b/test_admin.dart deleted file mode 100644 index 1190e49df..000000000 --- a/test_admin.dart +++ /dev/null @@ -1,2 +0,0 @@ -import 'package:dart_firebase_admin/dart_firebase_admin.dart'; -void main() {} From b5397444e785db2553018454b8a42d648d7fd90a Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Mon, 13 Apr 2026 19:49:47 +0000 Subject: [PATCH 7/9] fix(dart): null check handling and rename dart_firebase_admin The firebase-admin-dart repository recently renamed the primary package from `dart_firebase_admin` to `firebase_admin_sdk`. This updates all the references and overrides in the quickstarts to match the new package name, fixing a CI version solving failure where the `dart_firebase_admin/pubspec.yaml` was not found on the `main` branch. Also updates the overrides' `ref: master` to `ref: main` where applicable since the repository uses `main`. Also fixes a null type error in parameter parsing. Co-authored-by: jhuleatt <3759507+jhuleatt@users.noreply.github.com> From 8e2da6f754ea641dabfb01011a2b94227e0899d9 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Mon, 13 Apr 2026 19:53:59 +0000 Subject: [PATCH 8/9] feat(dart): add resize-image quickstart and update dependencies Adds a new Dart cloud functions quickstart `resize-image` which uses `firebase_functions` to expose an HTTP endpoint `imageOptimizer`. It dynamically downloads an image from Cloud Storage, resizes it using `package:image` based on `width` and `height` query parameters (falling back to a default via `defineInt`), and saves it back to the Cloud Storage bucket with proper `Cache-Control`. Subsequent requests to the same image dimensions are served directly from the cache. Also updates all dart quickstarts to use `firebase_admin_sdk` since the repository recently renamed the primary package from `dart_firebase_admin` to `firebase_admin_sdk`, and points overrides to the `main` branch. Co-authored-by: jhuleatt <3759507+jhuleatt@users.noreply.github.com> From 37f48423bcfa1e4805094efe67fa3d73070b21af Mon Sep 17 00:00:00 2001 From: Jeff Huleatt <3759507+jhuleatt@users.noreply.github.com> Date: Tue, 14 Apr 2026 10:53:28 -0400 Subject: [PATCH 9/9] refine sample --- .gitignore | 2 + Dart/quickstarts/resize-image/bin/server.dart | 123 +++++++++--------- Dart/quickstarts/resize-image/firebase.json | 12 ++ Dart/quickstarts/resize-image/pubspec.yaml | 11 +- 4 files changed, 81 insertions(+), 67 deletions(-) diff --git a/.gitignore b/.gitignore index 127eafecb..ebf231129 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,8 @@ **/.firebase **/.firebaserc **/.runtimeconfig.json +**/functions.yaml +**/.env.local */npm-debug.log lerna-debug.log *~ diff --git a/Dart/quickstarts/resize-image/bin/server.dart b/Dart/quickstarts/resize-image/bin/server.dart index 7a0be6a50..b6e511212 100644 --- a/Dart/quickstarts/resize-image/bin/server.dart +++ b/Dart/quickstarts/resize-image/bin/server.dart @@ -1,9 +1,8 @@ import 'dart:typed_data'; -import 'package:firebase_admin_sdk/firebase_admin_sdk.dart'; +import 'package:google_cloud_storage/google_cloud_storage.dart' + show ObjectMetadata, NotFoundException; import 'package:firebase_functions/firebase_functions.dart'; -import 'package:google_cloud_storage/google_cloud_storage.dart'; -import 'package:googleapis/storage/v1.dart'; import 'package:image/image.dart'; final defaultWidth = defineInt( @@ -11,54 +10,53 @@ final defaultWidth = defineInt( ParamOptions(defaultValue: 300), ); -// Lazily initialize the default app when needed to avoid duplication. -FirebaseApp? _app; -FirebaseApp get app { - _app ??= FirebaseApp.initializeApp(); - return _app!; -} - void main(List args) async { await fireUp(args, (firebase) { + /// An https function that resizes images in Cloud Storage. + /// It creates a separate Storage folder to cache stored images + /// so that it does not need to resize an image twice. + /// + /// It returns an HTTP redirect to the public Storage download URL. + /// + /// The query params it accepts are: + /// - image: the image file path in Cloud Storage + /// - width (optional): the width in pixels to resize to + /// + /// Example call: https://?image=myFile.png&width=400 firebase.https.onRequest(name: 'imageOptimizer', (request) async { - final pathSegments = request.url.pathSegments; - if (pathSegments.isEmpty || pathSegments.last.isEmpty) { - return Response( - 400, - body: 'Missing storage object ID in the request path.', + // Parse arguments from query params in the URL + final queryParams = request.url.queryParameters; + final imageFileName = queryParams['image']; + if (imageFileName == null) { + throw InvalidArgumentError( + 'No image provided. Include the image file name as a query param.', ); } - final storageObjectId = pathSegments.join('/'); - - final queryParams = request.url.queryParameters; - final width = queryParams.containsKey('width') - ? (int.tryParse(queryParams['width']!) ?? defaultWidth.value()) - : defaultWidth.value(); - final height = queryParams.containsKey('height') - ? int.tryParse(queryParams['height']!) - : null; - - if (width <= 0) { - return Response(400, body: 'Invalid width parameter.'); + var width = int.tryParse(queryParams['width'] ?? ""); + if (width == null) { + logger.info( + 'Cloud not parse width from query params. Using default width.', + ); + width = defaultWidth.value(); } - final bucket = app.storage().bucket(); - - final cachedFileName = height == null - ? 'image-optimizer-cache/${width}w-$storageObjectId' - : 'image-optimizer-cache/${width}w-${height}h-$storageObjectId'; + // Get the storage bucket from the built-in parameter + // https://firebase.google.com/docs/functions/config-env#built-in-parameters + final bucketName = storageBucket.value(); + final bucket = firebase.adminApp.storage().bucket(bucketName); + // Return early if the image has been resized before + final cachedFileName = 'image-optimizer-cache/${width}w-${imageFileName}'; try { - await bucket.storage.objectMetadata(bucket.name, cachedFileName); - final downloadUrl = await app.storage().getDownloadURL( + await bucket.storage.objectMetadata(bucketName, cachedFileName); + final downloadUrl = await firebase.adminApp.storage().getDownloadURL( bucket, cachedFileName, ); + logger.log('Cache hit. Using existing resized image.'); return Response.movedPermanently(downloadUrl); - } on DetailedApiRequestError catch (e) { - if (e.status != 404) { - rethrow; - } + } on NotFoundException { + logger.log('Cache miss. Resizing image to width ${width}'); } // Download original image @@ -66,45 +64,52 @@ void main(List args) async { try { originalBytes = await bucket.storage.downloadObject( bucket.name, - storageObjectId, + imageFileName, + ); + } on NotFoundException { + throw InvalidArgumentError( + 'Image ${imageFileName} does not exist in bucket ${bucketName}.', ); - } on DetailedApiRequestError catch (e) { - if (e.status == 404) { - return Response(404, body: 'Original image not found.'); - } - rethrow; } // Decode image final originalImage = decodeImage(Uint8List.fromList(originalBytes)); if (originalImage == null) { - return Response(400, body: 'Failed to decode original image.'); + throw InvalidArgumentError( + 'Failed to decode image. Are you sure it was an image file?', + ); } - // Resize image - final resizedImage = copyResize( - originalImage, - width: width, - height: height, - maintainAspect: true, - ); - - // Encode image - final encodedBytes = encodeNamedImage(storageObjectId, resizedImage); - if (encodedBytes == null) { - return Response(500, body: 'Failed to encode resized image.'); + // Resize if needed + var encodedBytes; + if (originalImage.width >= width) { + final resizedImage = copyResize( + originalImage, + width: width, + maintainAspect: true, + ); + encodedBytes = encodeNamedImage(imageFileName, resizedImage); + if (encodedBytes == null) { + throw InternalError('Failed to encode resized image.'); + } + } else { + logger.info( + 'Image is already smaller than the requested width. No need to resize.', + ); + encodedBytes = originalBytes; } - // Upload resized image + // Upload resized image to cache directory await bucket.storage.uploadObject( bucket.name, cachedFileName, encodedBytes, + // Tell clients to cache the resized image to reduce repeat requests metadata: ObjectMetadata(cacheControl: 'public, max-age=86400'), ); // Return download URL - final downloadUrl = await app.storage().getDownloadURL( + final downloadUrl = await firebase.adminApp.storage().getDownloadURL( bucket, cachedFileName, ); diff --git a/Dart/quickstarts/resize-image/firebase.json b/Dart/quickstarts/resize-image/firebase.json index 92ac4f167..adda93f17 100644 --- a/Dart/quickstarts/resize-image/firebase.json +++ b/Dart/quickstarts/resize-image/firebase.json @@ -2,5 +2,17 @@ "functions": { "source": ".", "codebase": "dart-quickstarts-resize-image" + }, + "emulators": { + "functions": { + "port": 5001 + }, + "storage": { + "port": 9199 + }, + "ui": { + "enabled": true + }, + "singleProjectMode": true } } diff --git a/Dart/quickstarts/resize-image/pubspec.yaml b/Dart/quickstarts/resize-image/pubspec.yaml index 9346e3d7e..363dac322 100644 --- a/Dart/quickstarts/resize-image/pubspec.yaml +++ b/Dart/quickstarts/resize-image/pubspec.yaml @@ -6,24 +6,19 @@ environment: sdk: ^3.11.0 dependencies: - firebase_admin_sdk: ^0.5.0 + image: ^4.8.0 + path: ^1.9.1 firebase_functions: git: url: https://github.com/firebase/firebase-functions-dart ref: main - google_cloud_storage: ^0.6.0 - image: ^4.8.0 - path: ^1.9.1 + intl: ^0.20.2 dev_dependencies: build_runner: ^2.10.5 lints: ^6.0.0 dependency_overrides: - firebase_functions: - git: - url: https://github.com/firebase/firebase-functions-dart - ref: main firebase_admin_sdk: git: url: https://github.com/firebase/firebase-admin-dart