2017-05-16 6 views
3

私は、イメージを取得し、ターゲットファイルのサイズが指定されたサイズよりも小さく、できるだけ大きくなるようにする関数を探しています。イメージをサイズ変更して特定の最大値を取得します。ファイルサイズ

なぜなら、vcardを最大で作成する理由があります。写真のサイズは224KBです。
(アップルまたはvCardの制限: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

可能な解決策の1つは、jpegの品質設定を変更することです。

多くの画質設定を繰り返すのではなく、画質設定の見積もりを作成しました。

イメージのファイルサイズが最良の品質で取得され、見積もりサイズを使用して、ファイルサイズの下にある品質設定を推測します。可能な限り近づくために、品質設定を上下に移動し、ファイルサイズを数回確認します。

ファイルサイズが必要なサイズより小さく、必要なサイズのしきい値パーセンテージより高い品質設定が見つかった場合、その品質設定が使用されるしきい値サイズがあります。

しきい値が見つからない場合は、合格した最高の品質設定を使用します。

品質設定が見つからない場合は、非常に低い設定になります。

品質設定がゼロの場合、失敗しました。

// 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 
を使用する方法

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

必要

機能

関連する問題