datasync-blob 1.1.24 → 1.1.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/DsBlob.js +165 -153
- package/package.json +1 -1
|
@@ -20,87 +20,131 @@ class DsBlob extends _react.Component {
|
|
|
20
20
|
this.debugging = false;
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
23
|
+
//-----------------------------------------
|
|
24
|
+
/**
|
|
25
|
+
* PROTOTYPE : uploadToDatasyncCloud
|
|
26
|
+
* Purpose : Upload binary data to My Custom Cloud server using Datasync SncPushCloud endpoint and return the accessible URL for the uploaded file.
|
|
27
|
+
* @param base64Data
|
|
28
|
+
* @param fileName
|
|
29
|
+
*/
|
|
30
|
+
uploadToDatasyncCloud = async pictureBlob => {
|
|
31
|
+
try {
|
|
32
|
+
const formData = new FormData();
|
|
33
|
+
let cloud_filename = pictureBlob.cloud_url_prefix.split('/').pop(); // Extract filename from cloud_url_prefix
|
|
34
|
+
|
|
35
|
+
console.log("Uploading to Datasync Cloud with filename:", cloud_filename);
|
|
36
|
+
formData.append('action', "syncPushCloud");
|
|
37
|
+
//formData.append('filename', `${CGUID()}.jpg`);
|
|
38
|
+
formData.append('filename', cloud_filename); // Extract filename from cloud_url_prefix
|
|
39
|
+
|
|
40
|
+
// Convert blob URL to actual binary data
|
|
41
|
+
let binaryString;
|
|
42
|
+
if (pictureBlob.isBlobUrl && pictureBlob.data.startsWith('blob:')) {
|
|
43
|
+
// Fetch the blob URL to get actual file content
|
|
44
|
+
console.log('Fetching blob URL:', pictureBlob.data);
|
|
45
|
+
const blobResponse = await fetch(pictureBlob.data);
|
|
46
|
+
const blob = await blobResponse.blob();
|
|
47
|
+
|
|
48
|
+
// Convert blob to ArrayBuffer then to Uint8Array
|
|
49
|
+
const arrayBuffer = await blob.arrayBuffer(); // Raw binary JPEG data
|
|
50
|
+
const uint8Array = new Uint8Array(arrayBuffer); // ← THIS CONTAINS THE GENUINE JPEG FILE BINARY DATA
|
|
51
|
+
|
|
52
|
+
// Convert to base64 string for transmission (chunked to avoid stack overflow)
|
|
53
|
+
let binaryStr = '';
|
|
54
|
+
const chunkSize = 8192; // Process in 8KB chunks to avoid stack overflow
|
|
55
|
+
for (let i = 0; i < uint8Array.length; i += chunkSize) {
|
|
56
|
+
const chunk = uint8Array.slice(i, i + chunkSize);
|
|
57
|
+
binaryStr += String.fromCharCode(...chunk);
|
|
58
|
+
}
|
|
59
|
+
binaryString = btoa(binaryStr); // ← THIS CONTAINS THE GENUINE JPEG FILE AS BASE64 STRING
|
|
60
|
+
|
|
61
|
+
console.log('Converted blob URL to binary data, size:', uint8Array.length);
|
|
62
|
+
} else if (Array.isArray(pictureBlob.binaryData)) {
|
|
63
|
+
// Convert Uint8Array or regular array to base64 string
|
|
64
|
+
const uint8Array = new Uint8Array(pictureBlob.binaryData);
|
|
65
|
+
let binaryStr = '';
|
|
66
|
+
const chunkSize = 8192;
|
|
67
|
+
for (let i = 0; i < uint8Array.length; i += chunkSize) {
|
|
68
|
+
const chunk = uint8Array.slice(i, i + chunkSize);
|
|
69
|
+
binaryStr += String.fromCharCode(...chunk);
|
|
70
|
+
}
|
|
71
|
+
binaryString = btoa(binaryStr);
|
|
72
|
+
} else if (pictureBlob.binaryData instanceof Uint8Array) {
|
|
73
|
+
// Already a Uint8Array, convert to base64
|
|
74
|
+
let binaryStr = '';
|
|
75
|
+
const chunkSize = 8192;
|
|
76
|
+
for (let i = 0; i < pictureBlob.binaryData.length; i += chunkSize) {
|
|
77
|
+
const chunk = pictureBlob.binaryData.slice(i, i + chunkSize);
|
|
78
|
+
binaryStr += String.fromCharCode(...chunk);
|
|
79
|
+
}
|
|
80
|
+
binaryString = btoa(binaryStr);
|
|
81
|
+
} else {
|
|
82
|
+
// Assume it's already a string
|
|
83
|
+
binaryString = pictureBlob.binaryData || "";
|
|
40
84
|
}
|
|
85
|
+
formData.append('binary', binaryString);
|
|
86
|
+
console.log("binaryString ->", binaryString.substring(0, 100) + '...'); // Log the beginning of the base64 string for debugging
|
|
41
87
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
88
|
+
const results = await fetch('http://localhost:8888/datasync-service/Sync.php', {
|
|
89
|
+
method: 'POST',
|
|
90
|
+
body: formData
|
|
91
|
+
});
|
|
92
|
+
if (!results.ok) {
|
|
93
|
+
throw new Error(`HTTP error! status: ${response.statusText}`);
|
|
94
|
+
}
|
|
95
|
+
let sync_push_cloud_response = await results.json();
|
|
96
|
+
|
|
97
|
+
// Try to parse as JSON
|
|
98
|
+
try {
|
|
99
|
+
if (!sync_push_cloud_response.state) throw new Error(`syncPushCloud returned error: ${sync_push_cloud_response.message}`);else console.log('syncPushCloud upload response:', sync_push_cloud_response.message);
|
|
100
|
+
return true; // Return true on successful upload
|
|
101
|
+
} catch (parseError) {
|
|
102
|
+
console.error('syncPushCloud : JSON parse error:', parseError);
|
|
103
|
+
throw new Error(`syncPushCloud raised error: ${parseError}`);
|
|
46
104
|
}
|
|
105
|
+
} catch (error) {
|
|
106
|
+
if (true) {
|
|
107
|
+
console.error('syncPushCloud upload error details:', error);
|
|
108
|
+
}
|
|
109
|
+
throw error;
|
|
47
110
|
}
|
|
111
|
+
};
|
|
48
112
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
if (!this.props.reduceImage) {
|
|
65
|
-
alert("L'image est trop haute, la hauteur maximale est de " + this.props.maxHeight);
|
|
66
|
-
return;
|
|
113
|
+
//-----------------------------------------
|
|
114
|
+
convert_blob_picture_into_cloud_file = async pictureBlob => {
|
|
115
|
+
try {
|
|
116
|
+
console.log("Received pictureBlob in uploadPicture:cloud_url_prefix -> ", pictureBlob.cloud_url_prefix);
|
|
117
|
+
if (!pictureBlob || !pictureBlob.data) {
|
|
118
|
+
//Reset picture
|
|
119
|
+
this.setPicture("");
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
if (pictureBlob.isBlobUrl && pictureBlob.data.startsWith('blob:') && pictureBlob.cloud_url_prefix) {
|
|
123
|
+
let updloadSucces = await this.uploadToDatasyncCloud(pictureBlob); // Upload the image to custom Datasync cloud
|
|
124
|
+
if (updloadSucces) {
|
|
125
|
+
//Clear the data URL to free memory since the image is now uploaded and accessible via cloud URL
|
|
126
|
+
if (pictureBlob.data && pictureBlob.data.startsWith('blob:')) {
|
|
127
|
+
URL.revokeObjectURL(pictureBlob.data);
|
|
67
128
|
}
|
|
68
|
-
|
|
69
|
-
|
|
129
|
+
this.setData(pictureBlob.cloud_url_prefix);
|
|
130
|
+
//inform parent component of the new cloud URL for the uploaded image
|
|
131
|
+
this.props.uploadPicture({
|
|
132
|
+
data: pictureBlob.cloud_url_prefix
|
|
133
|
+
});
|
|
134
|
+
} else {
|
|
135
|
+
console.error("Upload to Datasync cloud failed - no success response received");
|
|
136
|
+
throw new Error("Upload to Datasync cloud failed - no success response received");
|
|
70
137
|
}
|
|
71
138
|
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
//Build 2d picture
|
|
75
|
-
canvas.width = width;
|
|
76
|
-
canvas.height = height;
|
|
77
|
-
context = canvas.getContext('2d');
|
|
78
|
-
context.drawImage(imageSource, 0, 0, width, height);
|
|
79
|
-
|
|
80
|
-
//Jpeg conversion
|
|
81
|
-
let jpegCompressionRatio = this.props.jpegQuality && this.props.jpegQuality > 0 && this.props.jpegQuality < 1 ? this.props.jpegQuality : 1;
|
|
82
|
-
let canvasData = canvas.toDataURL('image/jpg', jpegCompressionRatio); //Jpeg conversion
|
|
83
|
-
|
|
84
|
-
if (this.debugging) console.log("jpegCompressionRatio->", jpegCompressionRatio, " canvasData.length = ", canvasData.length);
|
|
85
|
-
const processedData = this.props.removebase64 ? canvasData ? canvasData.substring("data:image/png;base64".length) : "" : canvasData ? canvasData : "";
|
|
86
|
-
this.setData(processedData);
|
|
87
|
-
if (this.props.removebase64) {
|
|
88
|
-
//remove base64 prefix if property is set
|
|
89
|
-
this.props.uploadPicture({
|
|
90
|
-
data: processedData
|
|
91
|
-
});
|
|
92
|
-
} else {
|
|
93
|
-
//Keep base 64 prefix as it is
|
|
94
|
-
this.props.uploadPicture({
|
|
95
|
-
data: processedData
|
|
96
|
-
});
|
|
139
|
+
} catch (error) {
|
|
140
|
+
console.error("Upload error:", error);
|
|
97
141
|
}
|
|
98
142
|
};
|
|
143
|
+
|
|
99
144
|
//-----------------------------------------------------------------------------------------------------------------------------------------
|
|
100
|
-
|
|
145
|
+
reduceBase64Image = e => {
|
|
101
146
|
let imageSource = e.path && e.path[0] || e.srcElement; //Safari compliancy
|
|
102
147
|
|
|
103
|
-
alert("reduceBinaryImage !");
|
|
104
148
|
if (this.debugging) console.log("imageSource = ", imageSource);
|
|
105
149
|
var canvas = document.createElement('canvas'),
|
|
106
150
|
context,
|
|
@@ -147,102 +191,77 @@ class DsBlob extends _react.Component {
|
|
|
147
191
|
}
|
|
148
192
|
}
|
|
149
193
|
|
|
194
|
+
//Compute jpeg compression ratio
|
|
195
|
+
let jpegCompressionRatio = this.props.jpegQuality && this.props.jpegQuality > 0 && this.props.jpegQuality < 1 ? this.props.jpegQuality : 1;
|
|
196
|
+
|
|
150
197
|
//Build 2d picture
|
|
151
198
|
canvas.width = width;
|
|
152
199
|
canvas.height = height;
|
|
153
200
|
context = canvas.getContext('2d');
|
|
154
201
|
context.drawImage(imageSource, 0, 0, width, height);
|
|
202
|
+
if (this.props.cloud_storage) {
|
|
203
|
+
canvas.toBlob(async blob => {
|
|
204
|
+
if (blob) {
|
|
205
|
+
console.log("Binary blob created, size:", blob.size);
|
|
206
|
+
if (this.debugging) console.log("jpegCompressionRatio->", jpegCompressionRatio, " blob.size = ", blob.size);
|
|
207
|
+
|
|
208
|
+
// Fallback: use blob URL for display but keep binary data
|
|
209
|
+
const blobUrl = URL.createObjectURL(blob);
|
|
210
|
+
|
|
211
|
+
// Convert blob to ArrayBuffer to maintain genuine binary data
|
|
212
|
+
const reader = new FileReader();
|
|
213
|
+
reader.onload = () => {
|
|
214
|
+
const binaryData = reader.result; // ArrayBuffer - genuine binary data
|
|
215
|
+
console.log("Fallback: Using binary data, size:", binaryData.byteLength);
|
|
216
|
+
|
|
217
|
+
//Call the upload callback with both blob URL for display and binary data for upload
|
|
218
|
+
this.convert_blob_picture_into_cloud_file({
|
|
219
|
+
data: blobUrl,
|
|
220
|
+
// For display in img tag
|
|
221
|
+
binaryData: binaryData,
|
|
222
|
+
// Genuine JPEG binary stream
|
|
223
|
+
cloud_url_prefix: this.props.cloud_url_prefix,
|
|
224
|
+
// Pass cloud URL prefix if needed for parent component
|
|
225
|
+
isBlobUrl: true // Flag to track blob URLs for cleanup
|
|
226
|
+
});
|
|
227
|
+
};
|
|
228
|
+
reader.readAsArrayBuffer(blob);
|
|
229
|
+
} else {
|
|
230
|
+
console.error("Failed to create blob from canvas");
|
|
231
|
+
}
|
|
232
|
+
}, 'image/jpeg', jpegCompressionRatio);
|
|
233
|
+
} else {
|
|
234
|
+
//Jpeg conversion
|
|
155
235
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
const reader = new FileReader();
|
|
168
|
-
reader.onload = () => {
|
|
169
|
-
const binaryData = reader.result; // ArrayBuffer - genuine binary data
|
|
170
|
-
console.log("Fallback: Using binary data, size:", binaryData.byteLength);
|
|
171
|
-
|
|
172
|
-
// Store both display URL and binary data
|
|
173
|
-
this.setData(blobUrl, binaryData);
|
|
174
|
-
this.props.uploadPicture({
|
|
175
|
-
data: blobUrl,
|
|
176
|
-
// For display in img tag
|
|
177
|
-
binaryData: binaryData,
|
|
178
|
-
// Genuine JPEG binary stream
|
|
179
|
-
cloud_url_prefix: this.props.cloud_url_prefix,
|
|
180
|
-
// Pass cloud URL prefix if needed for parent component
|
|
181
|
-
isBlobUrl: true // Flag to track blob URLs for cleanup
|
|
182
|
-
});
|
|
183
|
-
};
|
|
184
|
-
reader.readAsArrayBuffer(blob);
|
|
185
|
-
} else {
|
|
186
|
-
console.error("Failed to create blob from canvas");
|
|
187
|
-
}
|
|
188
|
-
}, 'image/jpeg', jpegCompressionRatio);
|
|
236
|
+
let canvasData = canvas.toDataURL('image/jpg', jpegCompressionRatio); //Jpeg conversion
|
|
237
|
+
|
|
238
|
+
if (this.debugging) console.log("jpegCompressionRatio->", jpegCompressionRatio, " canvasData.length = ", canvasData.length);
|
|
239
|
+
const processedData = canvasData ? canvasData : "";
|
|
240
|
+
this.setData(processedData);
|
|
241
|
+
|
|
242
|
+
//Keep base 64 prefix as it is
|
|
243
|
+
this.props.uploadPicture({
|
|
244
|
+
data: processedData
|
|
245
|
+
});
|
|
246
|
+
}
|
|
189
247
|
};
|
|
190
248
|
|
|
191
249
|
//-----------------------------------------------------------------------------------------------------------------------------------------
|
|
192
250
|
storeBase64ImageToImg = e => {
|
|
193
|
-
var
|
|
194
|
-
|
|
251
|
+
var DOM_image = document.createElement('img');
|
|
252
|
+
DOM_image.onload = this.reduceBase64Image;
|
|
195
253
|
console.log("storeBase64ImageToImg:e.currentTarget.result = ", e.currentTarget.result);
|
|
196
|
-
|
|
197
|
-
image.src = e.currentTarget.result;
|
|
198
|
-
};
|
|
199
|
-
|
|
200
|
-
//-----------------------------------------------------------------------------------------------------------------------------------------
|
|
201
|
-
storeBinaryImageToImg = e => {
|
|
202
|
-
var image = document.createElement('img');
|
|
203
|
-
//2Do DEBUG image.onload = this.reduceImage;
|
|
204
|
-
console.log("storeBinaryImageToImg:e.currentTarget.result = ", e.currentTarget.result);
|
|
205
|
-
alert("storeBinaryImageToImg !");
|
|
206
|
-
// Convert ArrayBuffer to Blob URL since image.src cannot accept ArrayBuffer directly
|
|
207
|
-
// Use the detected image type from the original file
|
|
208
|
-
const imageType = this.currentImageType || 'image/jpeg'; // fallback to jpeg
|
|
209
|
-
const blob = new Blob([e.currentTarget.result], {
|
|
210
|
-
type: imageType
|
|
211
|
-
});
|
|
212
|
-
const blobUrl = URL.createObjectURL(blob);
|
|
213
|
-
image.src = blobUrl;
|
|
214
|
-
|
|
215
|
-
// Clean up blob URL after image loads to prevent memory leaks
|
|
216
|
-
image.onload = loadEvent => {
|
|
217
|
-
this.reduceBinaryImage(loadEvent);
|
|
218
|
-
URL.revokeObjectURL(blobUrl);
|
|
219
|
-
// Clear the stored image type
|
|
220
|
-
this.currentImageType = null;
|
|
221
|
-
};
|
|
254
|
+
DOM_image.src = e.currentTarget.result;
|
|
222
255
|
};
|
|
223
256
|
|
|
224
257
|
//-----------------------------------------------------------------------------------------------------------------------------------------
|
|
225
258
|
readImageAsBase64 = async aPictureFile => {
|
|
226
259
|
let _reader = new FileReader();
|
|
227
260
|
console.log("readImageAsBase64:aPictureFile = ", aPictureFile);
|
|
228
|
-
alert("readImageAsBase64 !");
|
|
229
261
|
_reader.onload = this.storeBase64ImageToImg;
|
|
230
262
|
_reader.readAsDataURL(aPictureFile); //The readAsDataURL() method of the FileReader interface is used to read the contents of the specified file's data as a base64 encoded string.
|
|
231
263
|
};
|
|
232
264
|
|
|
233
|
-
//-----------------------------------------------------------------------------------------------------------------------------------------
|
|
234
|
-
readImageAsBinary = async aPictureFile => {
|
|
235
|
-
let _reader = new FileReader();
|
|
236
|
-
console.log("readImageAsBinary:aPictureFile = ", aPictureFile);
|
|
237
|
-
alert("readImageAsBinary !");
|
|
238
|
-
|
|
239
|
-
// Store the image type for use in storeBinaryImageToImg
|
|
240
|
-
this.currentImageType = aPictureFile.type;
|
|
241
|
-
console.log("Detected image type:", this.currentImageType);
|
|
242
|
-
_reader.onload = this.storeBinaryImageToImg;
|
|
243
|
-
_reader.readAsArrayBuffer(aPictureFile); //The readAsArrayBuffer() method reads the file as genuine binary content without base64 conversion.
|
|
244
|
-
};
|
|
245
|
-
|
|
246
265
|
//-----------------------------------------------------------------------------------------------------------------------------------------
|
|
247
266
|
resetUpload = () => {
|
|
248
267
|
// Clean up any blob URLs before resetting
|
|
@@ -260,7 +279,7 @@ class DsBlob extends _react.Component {
|
|
|
260
279
|
cleanupBlobUrl = () => {
|
|
261
280
|
// Only show alert if not in test environment
|
|
262
281
|
if (typeof jest === 'undefined') {
|
|
263
|
-
|
|
282
|
+
console.log("cleanupBlobUrl !");
|
|
264
283
|
}
|
|
265
284
|
// Revoke blob URL if it exists to prevent memory leaks
|
|
266
285
|
if (this.state.data && this.state.data.startsWith('blob:')) {
|
|
@@ -318,11 +337,7 @@ class DsBlob extends _react.Component {
|
|
|
318
337
|
if (errCount == errs.length) {
|
|
319
338
|
//None new error occurs
|
|
320
339
|
if (this.debugging) console.log("readImageAsBase64::", file.name);
|
|
321
|
-
|
|
322
|
-
this.readImageAsBinary(file);
|
|
323
|
-
} else {
|
|
324
|
-
this.readImageAsBase64(file);
|
|
325
|
-
}
|
|
340
|
+
this.readImageAsBase64(file);
|
|
326
341
|
}
|
|
327
342
|
});
|
|
328
343
|
if (errs.length) {
|
|
@@ -345,8 +360,7 @@ class DsBlob extends _react.Component {
|
|
|
345
360
|
}
|
|
346
361
|
|
|
347
362
|
// Otherwise, treat as base64 and add appropriate prefix
|
|
348
|
-
|
|
349
|
-
return prefix + this.state.data;
|
|
363
|
+
return this.state.data;
|
|
350
364
|
};
|
|
351
365
|
|
|
352
366
|
//-----------------------------------------------------------------------------------------------------------------------------------------
|
|
@@ -356,7 +370,6 @@ class DsBlob extends _react.Component {
|
|
|
356
370
|
return this.state.binaryData || this.props.binaryData || null;
|
|
357
371
|
};
|
|
358
372
|
|
|
359
|
-
//-----------------------------------------------------------------------------------------------------------------------------------------
|
|
360
373
|
//-----------------------------------------------------------------------------------------------------------------------------------------
|
|
361
374
|
// Data getter and setter methods for read-write access
|
|
362
375
|
getData = () => {
|
|
@@ -464,7 +477,6 @@ DsBlob.propTypes = {
|
|
|
464
477
|
// Image processing options
|
|
465
478
|
reduceImage: _propTypes.default.bool,
|
|
466
479
|
jpegQuality: _propTypes.default.number,
|
|
467
|
-
removebase64: _propTypes.default.bool,
|
|
468
480
|
// Cloud storage options
|
|
469
481
|
cloud_storage: _propTypes.default.bool,
|
|
470
482
|
cloud_url_prefix: _propTypes.default.string,
|