基于图像方向生成图像大小

时间:2014-10-28 作者:Afterlame

I am working on a fairly complex redesign of a wordpress project. Currently I am working on the image implementation. The site is very image heavy and I want to provide the optimal image for each application. I thought about something like this:

1. Orientation

The image can be in landscape, portait or square format. Each has a different max-width. The optimal solution would be to provide a different version for each orientation.

Landscape
Portrait
Square

2. High PPI

I would also like to provide a @2x version of each image:

Landscape
Landscape@2x

Portrait
Portrait@2x

Square
Square@2x

3. Breakpoints

The final site comes with at least four breakpoints. I would also like to optimize the image for each breakpoint:

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    

The Problem

In the end, this gives me 24 generated images per image, which is a huge amount of generated data. Two thirds of that data will never be used (the two other orientations) and I would love to strip those out. add_image_size() does not take the image orientation into account.

Is there any way to only generate the images needed for the orientation of the image?


Update

TL;DR: I may have found a solution, code is at the bottom, further testing tomorrow.

Ok, I took a deep dive into the Wordpress Trac today, and I think I have got it.

It is hard to alter the generation of the add_image_size() function, so I took the wp_generate_attachment_metadata hook,

The images get generated in the wp_generate_attachment_metadata() function. It is hard to alter the function, because the matching wp_generate_attachment_metadata hook takes place, after the images have been generated.

Still, this was the best hook I have found for this purpose. I decided to create my own resized copies of the original image (WP_Image_Editor made that fairly easy) and include the newly generated images in the metadata of the original image.

So far this looks pretty good, except, that the progressbar stays on 100% until the images have been processed. This could be a problem with users leaving the page, before all images have been processed. The second problem was, that the custom generated images do not get deleted, if I delete the attachment. This is because of the get_intermediate_image_sizes() function, which looks for image sizes, added by add_image_size(). I have found the intermediate_image_sizes hook and want to try to add all possible image sizes to it tomorrow, in the meantime I have a quick solution, which makes use of the delete_attachment hook.

I will do further testing tomorrow and update this post.

Here is my code so far:

/**
 * 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\');
1 个回复
最合适的回答,由SO网友: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\');

结束

相关推荐

Removing blog page images

我有我的blog page here 然而,在我创建的一个网站上,我不太明白在哪里可以找到代码来去除我孩子主题上的图像。我使用的是2010年的代码,我已经设置了自己的博客模板页面,但它不起作用,所以我显然编辑了错误的文件。所以不是循环。php我想要编辑的文件,以便在主博客页面上删除这些图像?<?php /* How to display all other posts. */ ?> <?php else : ?> <div i