You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

能否使用PHP实现按用户指定KB大小压缩图片?

Can PHP compress images to a target file size (in KB)?

Absolutely! This is totally doable with PHP, though it’s not a one-step "set and forget" process—since image compression ratios don’t map directly to exact file sizes, we need an iterative approach to tweak quality until we hit our target. Let’s break this down.

Core Idea

The key here is to iteratively adjust the image compression quality, generate a temporary version of the image, check its file size, and keep refining until we get as close as possible to the target KB size. For JPEGs, we’ll adjust the quality percentage; for PNGs, we’ll tweak the compression level (since PNG is lossless, the level affects compression speed vs file size).

Full Implementation Code

Here’s a reusable function that handles both JPEG and PNG, and targets a specific KB size:

function compressImageToTargetSize(string $sourcePath, string $outputPath, int $targetKB): bool {
    // Get original image info
    $imageInfo = getimagesize($sourcePath);
    if (!$imageInfo) {
        error_log("Invalid image file: $sourcePath");
        return false;
    }
    $mimeType = $imageInfo['mime'];
    
    // Initialize image resource
    switch ($mimeType) {
        case 'image/jpeg':
            $image = imagecreatefromjpeg($sourcePath);
            $initialQuality = 80; // Start with a reasonable quality
            break;
        case 'image/png':
            $image = imagecreatefrompng($sourcePath);
            imagealphablending($image, false);
            imagesavealpha($image, true);
            $initialQuality = 6; // PNG compression level (0-9; higher = smaller file, slower)
            break;
        default:
            error_log("Unsupported image type: $mimeType");
            return false;
    }
    
    if (!$image) {
        error_log("Failed to create image resource from $sourcePath");
        return false;
    }
    
    $targetBytes = $targetKB * 1024;
    $currentQuality = $initialQuality;
    $minQuality = $mimeType === 'image/jpeg' ? 10 : 1; // Don't go lower than this to avoid garbage quality
    $maxQuality = $mimeType === 'image/jpeg' ? 100 : 9;
    $tolerance = 512; // Allow 512 bytes of difference (adjust as needed)
    
    // Iterate to find the right quality
    while (true) {
        // Create temporary file to check size
        $tempPath = tempnam(sys_get_temp_dir(), 'img_compress');
        
        // Save image with current quality
        if ($mimeType === 'image/jpeg') {
            imagejpeg($image, $tempPath, $currentQuality);
        } else {
            imagepng($image, $tempPath, $currentQuality);
        }
        
        $currentSize = filesize($tempPath);
        
        // Check if we're within tolerance
        if (abs($currentSize - $targetBytes) <= $tolerance) {
            // Copy temp file to output
            copy($tempPath, $outputPath);
            unlink($tempPath);
            imagedestroy($image);
            return true;
        }
        
        // Adjust quality
        if ($currentSize > $targetBytes) {
            // File is too big: lower quality/compression level
            if ($currentQuality <= $minQuality) {
                // Can't go lower—use the smallest possible file
                copy($tempPath, $outputPath);
                unlink($tempPath);
                imagedestroy($image);
                error_log("Can't reach target size; using smallest possible version");
                return true;
            }
            $currentQuality -= 5; // Adjust step size as needed
        } else {
            // File is too small: increase quality/compression level
            if ($currentQuality >= $maxQuality) {
                // Can't go higher—use the highest quality possible
                copy($tempPath, $outputPath);
                unlink($tempPath);
                imagedestroy($image);
                error_log("Target size is larger than original; using original quality");
                return true;
            }
            $currentQuality += 3; // Smaller step for finer adjustment
        }
        
        unlink($tempPath);
    }
}

// Example usage:
// Compress input.jpg to output.jpg, targeting 50KB
compressImageToTargetSize('input.jpg', 'output.jpg', 50);

Key Notes & Caveats

  • Tolerance Adjustment: The $tolerance variable lets you define how close you need to get to the target size. A smaller tolerance means more iterations but a more precise result.
  • Quality Limits: We set a minimum quality (10 for JPEG) to avoid producing completely unrecognizable images. You can tweak this based on your needs.
  • PNG Considerations: PNG is lossless, so increasing compression level (up to 9) makes the file smaller but takes longer to process. You won’t get drastic size reductions like with JPEG.
  • Memory Limits: Large images might hit PHP’s memory limit. If you get out-of-memory errors, adjust memory_limit in your php.ini file or use ini_set('memory_limit', '256M') at the top of your script.
  • File Type Support: This function handles JPEG and PNG—you can extend it to handle GIF or WebP by adding cases for their mime types and using the appropriate imagecreatefrom*/image* functions.

How to Let Users Input Target Size

To integrate user input, you’d just need a simple form that accepts the target KB value, then pass it to the function above. For example:

if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['image'], $_POST['target_kb'])) {
    $uploadedFile = $_FILES['image']['tmp_name'];
    $outputFile = 'compressed_' . $_FILES['image']['name'];
    $targetKB = (int)$_POST['target_kb'];
    
    if (compressImageToTargetSize($uploadedFile, $outputFile, $targetKB)) {
        echo "Success! Compressed image saved as $outputFile";
    } else {
        echo "Failed to compress image.";
    }
}

And the corresponding HTML form:

<form method="POST" enctype="multipart/form-data">
    <input type="file" name="image" accept="image/jpeg, image/png" required>
    <input type="number" name="target_kb" min="1" placeholder="Target size (KB)" required>
    <button type="submit">Compress Image</button>
</form>

内容的提问来源于stack exchange,提问作者David

火山引擎 最新活动