2017-05-16 113 views
3

我正在寻找一个功能,它需要一个图像,并确保目标文件的大小小于给定的大小,但尽可能大。调整图像大小以获得特定的最大值。文件大小

原因是创建一个vcard最大。照片大小为224KB。
(苹果或虚拟卡的限制:https://support.apple.com/en-us/HT202158

我想有这样的功能:

function (imageBase64, maxFileSize) 
{ 
    // Check if image is smaller 
    // If yes, return the old one. 
    // If not, reduce image size proportional to fit in maxFileSize 
    // return newImage 
} 

你有任何提示怎么解决呢?

我宁愿在js中做这个客户端。 但是,如果这是不可能的,我也接受服务器端的PHP解决方案。

回答

3

一个可能的解决方案是更改jpeg质量设置。

而不是重复许多质量设置我已经创建了图像大小估计的质量设置。

我以最佳质量获得图像的文件大小,然后使用估计大小猜测质量设置为文件大小。为了尽可能接近我上下移动质量设置并检查文件大小几次。

有一个阈值大小,如果发现质量设置的文件大小低于所需大小的文件大小并且高于所需大小的阈值百分比,则使用该质量设置。

如果未找到阈值,它将使用通过的最佳质量质量设置。

如果在找到质量设置时遇到问题,那么它只会给出非常低的设置。

如果质量设置为零,则表示失败。

功能所需

// 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); 
} 

如何使用

// 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