使用 PHP 和 ImageMagick 递归调整大小和命名图像时,如何根据现有文件名和扩展名最好地编写新文件

When using PHP and ImageMagick to resize and name images recursively, how to best write new files based on the existing filename and extension

我有一个包含 'source' 个图像的目录,我正在保存多个调整大小的文件。我希望给定目录中的所有 jpg 和 png 文件都根据其原始文件名(la filename-small.jpg、filename-medium.jpg 等)调整大小并使用新名称保存。我正在使用 ImageMagick。

SO 上的另一个问题中找到了获取所有文件的正则表达式,并且有所帮助——但我并不完全明白这里发生了什么。

我目前所拥有的是将原始文件扩展名放在文件名中间。虽然我明白为什么会这样,但我不确定解决此问题的最佳方法。

我怎样才能把它变成 filename-large.jpg 而不是 filename.jpg-large.jpg?

这是我目前拥有的:

<?php

    $directory = new RecursiveDirectoryIterator('source/assets/uploads/test');
    $iterator = new RecursiveIteratorIterator($directory);
    $images = new RegexIterator($iterator, '/^.+(.jpe?g|.png)$/i', RecursiveRegexIterator::GET_MATCH);

    $widths = [
        'small' => 400,
        'medium' => 800,
        'large' => 1000,
        'xlarge' => 1600,
    ];
    
    foreach($images as $image => $value) {

        // Set the original filename w/o the extension
        $originalFilename = $image;

        // set the extension based on the original
        // ideally conform the extension jpeg to jpg
        $originalExtension = '.jpg';
        
        // create a new Imagick instance
        $newImage = new Imagick($image);

        // strip out some junk
        $newImage->stripImage();

        // write a new file for each width 
        // and name it based on the original filename
        foreach ($widths as $key => $value) {
            // using 0 in the second $arg will keep the same image ratio
            $newImage->resizeImage($value,0, imagick::FILTER_LANCZOS, 0.9);
            $newImage->writeImage($originalFilename . '-' . $key . $originalExtension);
        }
    }

内森,

您正在使用括号捕获该扩展名。您想要捕获文件名,而不仅仅是扩展名。您可以使用非大括号 ((?:)) 对扩展变体进行分组。

$images = new RegexIterator($iterator, '/^(.+)\.(?:jpe?g|png)$/i', RecursiveRegexIterator::GET_MATCH);

我还在扩展名之前转义了文字点 (.)。

或者,您可以从 $image 变量中拆分扩展名和文件名:

preg_match('/^(.+)\.([^.]+)$/', $image, $matches);
// Set the original filename w/o the extension
$originalFilename = $matches[1];
// Set the original extension
$originalExtension = $matches[2];

最后,FWIW,如果我要这样做,我不会使用 RegexIterator,而是只是迭代目录,只对每个文件名使用 preg_match

$directory = dir('source/assets/uploads/test');
while(false !== ($entry = $directory->read())) {
    $result = preg_match('/^(.+)\.(jpe?g|png)$/i', $entry, $matches);
    if($result === false) {
      die('ERROR: `preg_match` failed on '.$entry);
    } else if($result === 0) {
      // not an image file
      continue;
    }
    // Set the original filename w/o the extension
    $originalFilename = $matches[1];
    // Set the original extension
    $originalExtension = $matches[2];

    // ... do the other things on the file
}

参考文献:

编辑:

对于 $matches 内的命名引用,您可以使用此修改后的正则表达式:

preg_match('/^(?P<filename>.+)\.(?P<extension>jpe?g|png)$/i', $entry, $matches);

?P<key> 是一个“占位符”,它将 key 指定为对该匹配项的引用。

您仍将 $matches 作为数组返回,而不是对象,但随后您可以使用该占位符作为索引访问值。

// Set the original filename w/o the extension
$originalFilename = $matches['filename'];
// Set the original extension
$originalExtension = $matches['extension'];

FWIW,数字索引也仍然存在。