Been really stumped by this problem. I’ve searched the web and haven’t found traces of info on it, but I believe it is a widespread issue.
See the HTML in this post. If I select more than 350 (the bounding value works for my iPhone, but it may vary based on device) photos the first 350 will upload just fine. For photos after 350 each one will fail. When this fails, the data returned is what appears to be an empty plist and the FileReader doesn’t error. Here is a sample of the bytes returned when it fails (appears to be an empty plist):
X$versionY$archiverT$topX$objects��_NSKeyedArchiver� Troot��U$null$)27ILQSU["
So, the question is: Is this a known issue I just haven’t found Apple’s documentation for? Is there a way to work around this without putting an arbitrary limit on the number of files you can select?
The HTML is below. I hosted it somewhere and debugged from my iPhone tethered to my Mac. I am looking at the image header to avoid dumping out more bytes than necessary and overloading the debugger console. I only log the contents of the first failure, but believe that all failure have the same contents.
<html>
<head>
<title>Tester</title>
</head>
<body>
<button id="selectButton">Select Photos</button>
<input type="file" id="fileInput" style="display: none;" accept="image/*" multiple>
<script>
document.getElementById('selectButton').addEventListener('click', function() {
document.getElementById('fileInput').click();
});
document.getElementById('fileInput').addEventListener('change', function(event) {
const files = event.target.files;
for (let i = 0; i < files.length; i++) {
const file = files[i];
testImage(file);
}
});
var savedOutput = false;
function testImage(file) {
var _reader = new window.FileReader(),
_fn = file.slice || file.mozSlice || file.webkitSlice || function(){return;},
_slice = _fn.call(file, 0, 3);
_reader.onloadend = function(_evt) {
var _isValid = false,
_bytes;
if (!_evt.currentTarget.error) {
_bytes = new window.Uint8Array(_evt.currentTarget.result);
if (
(_bytes[0] == 0xFF && _bytes[1] == 0xD8 && _bytes[2] == 0xFF) || //Check for jpg
(_bytes[0] == 0x42 && _bytes[1] == 0x4D) || //Check for BMP
(_bytes[0] == 0x89 && _bytes[1] == 0x50 && _bytes[2] == 0x4E) //Check for png
) {
_isValid = true;
} else {
if (_bytes[0] == 0xFF && _bytes[1] == 0xD8 && _bytes[2] == 0xFF) {
_isValid = true;
}
}
if(_bytes[0] == 0x00 && _bytes[1] == 0x00 && _bytes[2] == 0x00) { //Check for heic
_isValid = true;
}
}
console.log('File: ' + file.name + ' is a JPEG: ' + _isValid);
if (savedOutput === false && _isValid === false) {
savedOutput = true;
const decoder = new TextDecoder();
const text = decoder.decode(_bytes);
console.log('Failed Output: ', text);
}
}
_reader.readAsArrayBuffer(file);
}
</script>
</body>
</html>
I have tried this from more involved applications and it always fails. The failure seems related to file access.