For example, I have a compressed file, there are pictures, JS, HTML, etc., I would like to get through the JSZIp inside the picture Base64 code, but I get the picture compression Base64。
JSZip.loadAsync(data).then(function (zip) {
var imageSrc = {};
if(zip.files){
var strRegex = "(.jpg|.png|.gif|.ps|.jpeg)$";
var re=new RegExp(strRegex);
for(var i in zip.files){
var fileName = zip.files[i];
if (re.test(i.toLowerCase())){
var buffer = fileName._data.compressedContent,
str = _arrayBufferToBase64(buffer),
pIndex = i.indexOf('.'),
type = i.substr(pIndex + 1),
res = 'data:image/' + type + ';base64,';
imageSrc[i] = res + str;
}
}
}
});
function _arrayBufferToBase64( buffer ) {
var binary = '';
var bytes = new Uint8Array( buffer );
var len = bytes.byteLength;
for (var i = 0; i < len; i++) {
binary += String.fromCharCode( bytes[i] );
}
eturn window.btoa( binary );
}
fileName._data is an internal field and isn't meant to be used directly. To get the content, you need to call async. I'll also chain promises and use Blob urls instead of base64:
``js
JSZip.loadAsync(data).then(function (zip) {
var re = /(.jpg|.png|.gif|.ps|.jpeg)$/;
var promises = Object.keys(zip.files).filter(function (fileName) {
// don't consider non image files
return re.test(fileName.toLowerCase());
}).map(function (fileName) {
var file = zip.files[fileName];
return file.async("blob").then(function (blob) {
return [
fileName, // keep the link between the file name and the content
URL.createObjectURL(blob) // create an url. img.src = URL.createObjectURL(...) will work
];
});
});
//promisesis an array of promises,Promise.all` transforms it
// into a promise of arrays
return Promise.all(promises);
}).then(function (result) {
// we have here an array of [fileName, url]
// if you want the same result as imageSrc:
return result.reduce(function (acc, val) {
acc[val[0]] = val[1];
return acc;
}, {});
}).catch(function (e) {
console.error(e);
});
OMG,You're awesome! Thank you!
Official document is not detailed, can you tell me where there are detailed documentation
async is documented in this page but that won't help you much here. The documentation doesn't explain how to extract an image from a zip file. This is related to the issue #389.
It doesn't explain how to manipulate promises, list of promises, etc either.
en... thanks , now i still have a problem, i want to get value inside the function from outside, what should I do? for example , the above example
var ** imgData**;
JSZipUtils.getBinaryContent('zip/jszipTest.zip', function(err, data) {
JSZip.loadAsync(data).then(function (zip) {
...
}).map(function(){
...
}).then(function (result) {
// we have here an array of [fileName, url]
// if you want the same result as imageSrc:
return result.reduce(function (acc, val) {
acc[val[0]] = val[1];
return **acc**;
}, { });
})
}
then... How do i get the value of the **acc** assigned to **imgData**?
then will forward the returned value. Before the then block calling reduce, you have a promise which will contain an array of [name, BlobUrl]. After the reduce (which will create the object you want), you will have a promise which will contain what you want.
Add an other then block to get your value:
}).then(function (result) {
return result.reduce(...);
}).then(function (imgData) {
// now, you have imgData
});
The whole sequence of actions (from JSZipUtils.getBinaryContent to all the then callback) is asynchronous. If you declare imgData outside of JSZipUtils.getBinaryContent, be sure to wait for the last then callback to be called before using it.
If you have troubles working with promises and prefer callbacks, you can convert one into the other:
function prepareImgData(url, callback) {
JSZipUtils.getBinaryContent('zip/jszipTest.zip', function(err, data) {
JSZip.loadAsync(data).then(function (zip) {
// ... reduce
}).then(function (imgData) {
// assuming nodejs' style callback, with the error first
callback(null, imgData);
}).catch(function (e) {
callback(e, null);
});
});
}
thank you very much!
I appreciate your offer but I'll decline.
I'll close this issue as it seems to be fixed, please reopen it if it's not the case.
Most helpful comment
fileName._datais an internal field and isn't meant to be used directly. To get the content, you need to callasync. I'll also chain promises and use Blob urls instead of base64:``
js JSZip.loadAsync(data).then(function (zip) { var re = /(.jpg|.png|.gif|.ps|.jpeg)$/; var promises = Object.keys(zip.files).filter(function (fileName) { // don't consider non image files return re.test(fileName.toLowerCase()); }).map(function (fileName) { var file = zip.files[fileName]; return file.async("blob").then(function (blob) { return [ fileName, // keep the link between the file name and the content URL.createObjectURL(blob) // create an url. img.src = URL.createObjectURL(...) will work ]; }); }); //promisesis an array of promises,Promise.all` transforms it// into a promise of arrays
return Promise.all(promises);
}).then(function (result) {
// we have here an array of [fileName, url]
// if you want the same result as imageSrc:
return result.reduce(function (acc, val) {
acc[val[0]] = val[1];
return acc;
}, {});
}).catch(function (e) {
console.error(e);
});