web-dev-qa-db-ja.com

画像の向きに基づいて画像サイズを生成する

私はかなり複雑なワードプレスプロジェクトの再設計に取り組んでいます。現在私は画像の実装に取り​​組んでいます。このサイトは非常に画像が重いので、各アプリケーションに最適な画像を提供したいと思います。私はこのようなことについて考えました:

オリエンテーション

画像は、横長、縦撮り、または正方形のいずれでもかまいません。それぞれ最大幅が異なります。最適な解決策は、向きごとに異なるバージョンを提供することです。

Landscape
Portrait
Square

2.高PPI

各画像の@ 2xバージョンも提供したいと思います。

Landscape
Landscape@2x

Portrait
Portrait@2x

Square
Square@2x

3.ブレークポイント

最終サイトには少なくとも4つのブレークポイントがあります。また、ブレークポイントごとに画像を最適化したいと思います。

Breakpoint 1 | Breakpoint 2 | Breakpoint 3 | Breakpoint 4
-------------|--------------|--------------|-------------
Landscape    | Landscape    | Landscape    | Landscape   
Landscape@2x | Landscape@2x | Landscape@2x | Landscape@2x
             |              |              |
Portrait     | Portrait     | Portrait     | Portrait    
Portrait@2x  | Portrait@2x  | Portrait@2x  | Portrait@2x 
             |              |              |
Square       | Square       | Square       | Square      
Square@2x    | Square@2x    | Square@2x    | Square@2x    

問題

結局、これで1画像あたり24の生成画像が得られます。これは膨大な量の生成データです。そのデータの3分の2は決して使われず(他の2つの方向)、私はそれらを取り除きたいと思います。 add_image_size()は画像の向きを考慮に入れません。

画像の向きに必要な画像のみを生成する方法はありますか?


更新

TL; DR:解決策を見つけたかもしれません、コードは一番下にあり、明日さらにテストします。

さて、私は今日Wordpress Tracを深く掘り下げました、そして私はそれを手に入れたと思います。

add_image_size()関数の生成を変更するのは難しいので、wp_generate_attachment_metadataフックを取りました、

画像はwp_generate_attachment_metadata()関数で生成されます。対応するwp_generate_attachment_metadataフックは画像​​が生成された後に行われるため、関数を変更するのは困難です。

それでも、これは私がこの目的のために見つけた最高のフックでした。私はオリジナルのイメージの自分のサイズ変更されたコピーを作成することを決めました(WP_Image_Editorはそれをかなり簡単にしました)、そしてオリジナルのイメージのメタデータに新しく生成されたイメージを含めること。

これまでのところ、これはかなり良く見えますが、画像が処理されるまでプログレスバーは100%のままです。これは、すべての画像が処理される前にユーザーがページを離れると問題になる可能性があります。 2つ目の問題は、添付ファイルを削除してもカスタム生成された画像が削除されないことです。これは、get_intermediate_image_sizes()によって追加された、画像サイズを探すadd_image_size()関数のためです。私はintermediate_image_sizesフックを見つけて明日それにすべての可能な画像サイズを加えようとします、その間に私はdelete_attachmentフックを利用する迅速な解決策を持っています。

明日さらにテストを行い、この記事を更新します。

これが私のコードです。

/**
 * Generates custom image sizes, depending on the image orientation. Use the wp_generate_attachment_metadata hook!
 */
function r21_create_custom_image_sizes($meta) {

    // Initialize variables
    global $r21_image_sizes;
    $image_sizes = '';
    $new_meta = array();

    // Generate the full file path for the image
    $image['path'] = path_join(wp_upload_dir()['basedir'], $meta['file']);

    // Get the dimensions of the original image
    list($image['width'], $image['height'], $image['type']) = getimagesize($image['path']);

    // Check the image orientation
    if ($image['width'] > $image['height']) {
        // Landscape
        $image_sizes = r21_filter_custom_image_sizes($r21_image_sizes, 'landscape', true);

    } else if ($image['width'] < $image['height']) {
        // Portrait
        $image_sizes = r21_filter_custom_image_sizes($r21_image_sizes, 'portrait', true);

    } else {
        // Square
        $image_sizes = r21_filter_custom_image_sizes($r21_image_sizes, 'square', true);
    }

    // Iterate through the sizes to be generated
    foreach ($image_sizes as $size) {
        // TODO: Check if an image in the requested dimensions allready exists.

        // Create an instance of WP_Image_Editor for the original image
        $new_image = wp_get_image_editor($image['path']);

        // Resize the image
        $new_image->resize($size['width'], $size['height'], $size['crop']);

        // Save new image and store new meta data in variable
        $new_image_meta = $new_image->save();

        // Reflect back new metadata
        $meta['sizes'][$size['name']]['file'] = $new_image_meta['file'];
        $meta['sizes'][$size['name']]['width'] = $new_image_meta['width'];
        $meta['sizes'][$size['name']]['height'] = $new_image_meta['height'];
        $meta['sizes'][$size['name']]['mime-type'] = $new_image_meta['mime-type'];
    }

    return $meta;
}
add_filter('wp_generate_attachment_metadata', 'r21_create_custom_image_sizes');



/**
 * Deletes images, generated by r21_create_custom_image_sizes(). Use the delete_attachment hook!
 */
function r21_delete_custom_image_size_files($post_id) {
    $sizes_meta = wp_get_attachment_metadata($post_id)['sizes'];

    foreach ($sizes_meta as $size) {
        // TODO: Add support for wp_delete_file hook here
        @ unlink(path_join(wp_upload_dir()['path'], $size['file']));
    }
}
add_action('delete_attachment', 'r21_delete_custom_image_size_files');
2
Afterlame

これが私の実用的な解決策です。コードは文書化されているので、各機能が何をするのかはっきりしているはずです。

画像がアップロードされたら、wp_generate_attachment_metadataフィルタを使用して必要な画像を作成します。

生成された画像は、他の中間画像サイズと同様に、メタデータにもリストされます。そうすれば、他の画像サイズと同じように、それらを使って作業することができます。

もう一つの重要な部分は、生成された画像を削除するためにdelete_attachmentフィルタを使うことです。

// ==========================
// Custom Image Size Handling
// ==========================

/**
 * Removes default and plugin generated image sizes.
 * This is optional!
 */
function r21_remove_image_sizes($sizes) {
  unset($sizes['thumbnail']);
  unset($sizes['medium']);
  unset($sizes['large']);

  return $sizes;
}
add_filter('intermediate_image_sizes', 'r21_remove_image_sizes');
add_filter('intermediate_image_sizes_advanced', 'r21_remove_image_sizes');


/**
 * Generate a handle for thumbnail regeneration tools.
 * The custom images will always be regenerated after one of
 * the site wide image sizes have been regenerated.
 * The problem here is, that if there are no site wide image sizes
 * defined, you can not regenerate any custom size images.
 * To avoid this we create a 1x1 px image that works as handle, if there
 * are no other imge sizes.
 */
add_image_size( 'cstm-img-regeneration-handle' , 1, 1, array( 'left', 'top' ));


/**
 * Delete unneeded generated images and their metadata.
 * Also deletes images, generated in the filter, this is why
 * this function has to be used before the image generation function.
 *
 * @param array $attachment_meta
 * @return array
 */
function r21_remove_old_image_sizes($attachment_meta) {

  foreach ($attachment_meta['sizes'] as $size_name => $size_data) {
    // Ceck if image size is currently an active intermediate image size
    if (array_key_exists($size_name, get_intermediate_image_sizes())) { continue; }

    // Delete file
    @ unlink(path_join(r21_get_attachment_path_by('meta', $attachment_meta), $attachment_meta['sizes'][$size_name]['file']));

    // Delete metadata
    unset($attachment_meta['sizes'][$size_name]);
  }

  return $attachment_meta;
}
add_filter('wp_generate_attachment_metadata', 'r21_remove_old_image_sizes', 10, 1);


/**
 * Removes the the custom image regneration handle image, if existing.
 *
 * @return array Returns the metadata, without the handle image entry.
 */
function r21_remove_regeneration_hook_image($attachment_meta) {

  $name = 'cstm-img-regeneration-handle';

  // Check if image exists
  if (array_key_exists($name, $attachment_meta['sizes'])) {
    // Delete Image File
    @ unlink(path_join(r21_get_attachment_path_by('meta', $attachment_meta), $attachment_meta['sizes'][$name]['file']));

    // Delete Image Metadata
    unset($attachment_meta['sizes'][$name]);
  }

  return $attachment_meta;
}
add_filter('wp_generate_attachment_metadata', 'r21_remove_regeneration_hook_image', 10, 1);


/**
 * Generates custom image sizes, depending on the image orientation. Use the wp_generate_attachment_metadata hook!
 */
function r21_create_custom_image_sizes($meta) {

  // Initialize variables
  global $r21_image_sizes;
  $image_sizes = '';

  // Generate the full file path for the image
  $image['path'] = path_join(wp_upload_dir()['basedir'], $meta['file']);

  // Get the dimensions of the original image
  list($image['width'], $image['height'], $image['type']) = getimagesize($image['path']);

  // Check the image orientation
  if ($image['width'] > $image['height']) {
    // Landscape
    $image_sizes = r21_filter_custom_image_sizes($r21_image_sizes, 'landscape', true);

  } else if ($image['width'] < $image['height']) {
    // Portrait
    $image_sizes = r21_filter_custom_image_sizes($r21_image_sizes, 'portrait', true);

  } else {
    // Square
    $image_sizes = r21_filter_custom_image_sizes($r21_image_sizes, 'square', true);
  }

  // Iterate through the sizes to be generated
  foreach ($image_sizes as $size_name => $size) {
    // TODO: Check if an image in the requested dimensions allready exists.

    // Create an instance of WP_Image_Editor for the original image
    $new_image = wp_get_image_editor($image['path']);

    // Check if there is an error
    if (is_wp_error($new_image)) { continue; }

    // Resize the image
    $new_image->resize($size['width'], $size['height'], $size['crop']);

    // Save new image and store new meta data in variable
    $new_image_meta = $new_image->save();

    // Reflect back new metadata
    $meta['sizes'][$size_name]['file'] = $new_image_meta['file'];
    $meta['sizes'][$size_name]['width'] = $new_image_meta['width'];
    $meta['sizes'][$size_name]['height'] = $new_image_meta['height'];
    $meta['sizes'][$size_name]['mime-type'] = $new_image_meta['mime-type'];
  }

  return $meta;
}
add_filter('wp_generate_attachment_metadata', 'r21_create_custom_image_sizes', 10, 1);


/**
 * Deletes images, generated by r21_create_custom_image_sizes(). Use the delete_attachment hook!
 */
function r21_delete_custom_image_size_files($post_id) {
  $meta = wp_get_attachment_metadata($post_id);

  foreach ($meta['sizes'] as $size) {
    // TODO: Add support for wp_delete_file hook here
    @ unlink(path_join(r21_get_attachment_path_by('meta', $meta), $size['file']));
  }
}
add_action('delete_attachment', 'r21_delete_custom_image_size_files');
1
Afterlame