Skip to content

Commit fc61465

Browse files
committed
Support for GCS URIs in image resolver
1 parent 33dbee7 commit fc61465

File tree

5 files changed

+344
-7
lines changed

5 files changed

+344
-7
lines changed

.changeset/beige-carpets-visit.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@nutshelllabs/image': major
3+
---
4+
5+
Support for GS URIs in image resolving

packages/image/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
},
2424
"dependencies": {
2525
"@babel/runtime": "^7.20.13",
26+
"@google-cloud/storage": "^7.15.0",
2627
"@nutshelllabs/png-js": "^2.2.1",
2728
"cross-fetch": "^3.1.5"
2829
},

packages/image/src/resolve.js

+44-3
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,30 @@ import createCache from './cache';
99

1010
export const IMAGE_CACHE = createCache({ limit: 30 });
1111

12+
let GCS;
13+
if (!BROWSER) {
14+
// eslint-disable-next-line global-require
15+
GCS = require('@google-cloud/storage');
16+
}
17+
18+
const createGcsStorage = emulatorHost => {
19+
if (emulatorHost) {
20+
return new GCS.Storage({
21+
apiEndpoint: `http://${emulatorHost}`,
22+
customEndpoint: true,
23+
});
24+
}
25+
26+
return new GCS.Storage();
27+
};
28+
29+
let storage;
30+
export const configureStorage = (
31+
emulatorHost = process.env.GCS_EMULATOR_HOST,
32+
) => {
33+
storage = createGcsStorage(emulatorHost);
34+
};
35+
1236
const getAbsoluteLocalPath = src => {
1337
if (BROWSER) {
1438
throw new Error('Cannot check local paths in client-side environment');
@@ -143,13 +167,30 @@ const getImageFormat = body => {
143167
return extension;
144168
};
145169

170+
const resolveImageFromGcs = async uri => {
171+
if (BROWSER) {
172+
throw new Error('Cannot download from GCS in client-side environment');
173+
}
174+
175+
if (!storage) {
176+
configureStorage();
177+
}
178+
179+
const response = await GCS.File.from(uri, storage).download();
180+
return response[0];
181+
};
182+
146183
const resolveImageFromUrl = async src => {
147184
const { uri, body, headers, method = 'GET' } = src;
148185

149-
const data =
150-
!BROWSER && getAbsoluteLocalPath(uri)
151-
? await fetchLocalFile(uri)
186+
let data;
187+
if (!BROWSER && getAbsoluteLocalPath(uri)) {
188+
data = await fetchLocalFile(uri);
189+
} else {
190+
data = uri.startsWith('gs://')
191+
? await resolveImageFromGcs(uri)
152192
: await fetchRemoteFile(uri, { body, headers, method });
193+
}
153194

154195
const extension = getImageFormat(data);
155196

packages/image/tests/resolve.test.js

+13-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import fs from 'fs';
22
import path from 'path';
33

4-
import resolveImage, { IMAGE_CACHE } from '../src/resolve';
4+
import resolveImage, { IMAGE_CACHE, configureStorage } from '../src/resolve';
55

66
const jpgImageUrl = 'https://react-pdf.org/static/images/quijote1.jpg';
77
const pngImageUrl = 'https://react-pdf.org/static/images/quijote2.png';
@@ -70,6 +70,18 @@ describe('image resolveImage', () => {
7070
expect(image.height).toBeGreaterThan(0);
7171
});
7272

73+
test.skip('[Manual] Should render a png image from GCS', async () => {
74+
configureStorage('localhost:4443');
75+
76+
const gcsImageUrl =
77+
'gs://irisflow_input/1/1/brokerage_statement/e3eec7c7-96ff-4825-9485-06decad51544/test.jpg';
78+
const image = await resolveImage({ uri: gcsImageUrl });
79+
80+
expect(image.data).toBeTruthy();
81+
expect(image.width).toBeGreaterThan(0);
82+
expect(image.height).toBeGreaterThan(0);
83+
});
84+
7385
test('Should render a local image from src object', async () => {
7486
const image = await resolveImage({
7587
uri: './packages/layout/tests/assets/test.jpg',

0 commit comments

Comments
 (0)