Skip to content

Commit e931832

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

File tree

4 files changed

+59
-4
lines changed

4 files changed

+59
-4
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

+40-3
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,32 @@ import url from 'url';
33
import path from 'path';
44
import fetch from 'cross-fetch';
55

6+
import { Storage, File } from '@google-cloud/storage';
67
import PNG from './png';
78
import JPEG from './jpeg';
89
import createCache from './cache';
910

1011
export const IMAGE_CACHE = createCache({ limit: 30 });
1112

13+
const createGcsStorage = emulatorHost => {
14+
if (emulatorHost) {
15+
return new Storage({
16+
apiEndpoint: `http://${emulatorHost}`,
17+
customEndpoint: true,
18+
});
19+
}
20+
21+
return new Storage();
22+
};
23+
24+
let storage;
25+
26+
export const configureStorage = (
27+
emulatorHost = process.env.GCS_EMULATOR_HOST,
28+
) => {
29+
storage = createGcsStorage(emulatorHost);
30+
};
31+
1232
const getAbsoluteLocalPath = src => {
1333
if (BROWSER) {
1434
throw new Error('Cannot check local paths in client-side environment');
@@ -143,13 +163,30 @@ const getImageFormat = body => {
143163
return extension;
144164
};
145165

166+
const resolveImageFromGcs = async uri => {
167+
if (BROWSER) {
168+
throw new Error('Cannot download from GCS in client-side environment');
169+
}
170+
171+
if (!storage) {
172+
configureStorage();
173+
}
174+
175+
const response = await File.from(uri, storage).download();
176+
return response[0];
177+
};
178+
146179
const resolveImageFromUrl = async src => {
147180
const { uri, body, headers, method = 'GET' } = src;
148181

149-
const data =
150-
!BROWSER && getAbsoluteLocalPath(uri)
151-
? await fetchLocalFile(uri)
182+
let data;
183+
if (!BROWSER && getAbsoluteLocalPath(uri)) {
184+
data = await fetchLocalFile(uri);
185+
} else {
186+
data = uri.startsWith('gs://')
187+
? await resolveImageFromGcs(uri)
152188
: await fetchRemoteFile(uri, { body, headers, method });
189+
}
153190

154191
const extension = getImageFormat(data);
155192

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)