Eine mögliche Lösung ist die Änderung der JPEG-Qualitätseinstellung.
Anstatt viele Qualitätseinstellungen zu iterieren, habe ich eine Schätzung der Bildgrößen zu Qualitätseinstellungen erstellt.
Ich bekomme die Dateigröße des Bildes mit der besten Qualität dann verwenden Sie die Schätzungen Größen, um die Qualitätseinstellung zu erraten, um unter der Dateigröße zu sein. Um so nah wie möglich zu kommen, verschiebe ich die Qualitätseinstellungen nach oben und unten und überprüfe die Dateigröße einige Male.
Es gibt eine Schwellenwertgröße. Wenn eine Qualitätseinstellung gefunden wird, deren Dateigröße unter der erforderlichen Größe und über dem Schwellenwert der erforderlichen Größe liegt, wird diese Qualitätseinstellung verwendet.
Wenn der Schwellenwert nicht gefunden wird, verwendet er die beste Qualität der Qualitätseinstellung, die übergeben wurde.
Wenn es Probleme bei der Suche nach einer Qualitätseinstellung gab, wird nur eine sehr niedrige Einstellung angezeigt.
Wenn die Qualitätseinstellung Null ist, ist sie fehlgeschlagen.
Funktionen benötigt
// this function converts a image to a canvas image
function image2Canvas(image){
var canvas = document.createElement("canvas");
canvas.width = image.width;
canvas.height = image.height;
canvas.ctx = canvas.getContext("2d");
canvas.ctx.drawImage(image,0,0);
return canvas;
}
// warning try to limit calls to this function as it can cause problems on some systems
// as they try to keep up with GC
// This function gets the file size by counting the number of Base64 characters and
// calculating the number of bytes encoded.
function getImageFileSize(image,quality){ // image must be a canvas
return Math.floor(image.toDataURL("image/jpeg",quality).length * (3/4));
}
function qualityForSize(image,fileSize){
// These are approximations only
// and are the result of using a test image and finding the file size
// at quality setting 1 to 0.1 in 0.1 steps
const scalingFactors = [
5638850/5638850,
1706816/5638850,
1257233/5638850,
844268/5638850,
685253/5638850,
531014/5638850,
474293/5638850,
363686/5638850,
243578/5638850,
121475/5638850,
0, // this is added to catch the stuff ups.
]
var size = getImageFileSize(image,1); // get file size at best quality;
if(size <= fileSize){ // best quality is a pass
return 1;
}
// using size make a guess at the quality setting
var index = 0;
while(size * scalingFactors[index] > fileSize){ index += 1 }
if(index === 10){ // Could not find a quality setting
return 0; // this is bad and should not be used as a quality setting
}
var sizeUpper = size * scalingFactors[index-1]; // get estimated size at upper quality
var sizeLower = size * scalingFactors[index]; // get estimated size at lower quality
// estimate quality via linear interpolation
var quality = (1-(index/10)) + ((fileSize - sizeLower)/(sizeUpper-sizeLower)) * 0.1;
var qualityStep = 0.02; // the change in quality (this value gets smaller each try)
var numberTrys = 3; // number of trys to get as close as posible to the file size
var passThreshold = 0.90; // be within 90% of desiered file size
var passQualities = []; // array of quality settings that are under file size
while(numberTrys--){
var newSize = getImageFileSize(image,quality); // get the file size for quality guess
if(newSize <= fileSize && newSize/fileSize > passThreshold){ // does it pass?
return quality; // yes return quality
}
if(newSize > fileSize){ // file size too big
quality -= qualityStep; // try lower quality
qualityStep /= 2; // reduce the quality step for next try
}else{
passQualities.push(quality); // save this quality incase nothing get within the pass threashold
quality += qualityStep; // step the quality up.
qualityStep /= 2; // reduce the size of the next quality step
}
}
// could not find a quality setting so get the best we did find
if(passQualities.length > 0){ //check we did get a pass
passQualities.sort(); // sort to get best pass quality
return passQualities.pop(); // return best quality that passed
}
// still no good result so just default to next 0.1 step down
return 1-((index+1)/10);
}
Wie
// testImage is the image to set quality of
// the image must be loaded
var imgC = image2Canvas(testImage); // convert image to a canvas
var qualitySetting = qualityForSize(imgC,244000); // find the image quality to be under file size 244000
// convert to data URL
var dataURL = imgC.toDataURL("image/jpeg",qualitySetting);
// the saved file will be under 244000
verwenden