wake-up-neo.com

Generieren Sie die Bildgröße basierend auf der Bildorientierung

Ich arbeite an einem ziemlich komplexen Redesign eines WordPress-Projekts. Derzeit arbeite ich an der Image-Implementierung. Die Site ist sehr imagelastig und ich möchte für jede Anwendung das optimale Image bereitstellen. Ich dachte über so etwas nach:

1. Orientierung

Das Bild kann im Quer-, Porträt- oder Quadratformat vorliegen. Jedes hat eine andere maximale Breite. Die optimale Lösung wäre, für jede Ausrichtung eine andere Version bereitzustellen.

Landscape
Portrait
Square

2. Hoher PPI

Ich möchte auch eine @ 2x-Version von jedem Bild bereitstellen:

Landscape
[email protected]

Portrait
[email protected]

Square
[email protected]

3. Haltepunkte

Die endgültige Site enthält mindestens vier Haltepunkte. Ich möchte auch das Bild für jeden Haltepunkt optimieren:

Breakpoint 1 | Breakpoint 2 | Breakpoint 3 | Breakpoint 4
-------------|--------------|--------------|-------------
Landscape    | Landscape    | Landscape    | Landscape   
[email protected] | [email protected] | [email protected] | [email protected]
             |              |              |
Portrait     | Portrait     | Portrait     | Portrait    
[email protected]  | [email protected]  | [email protected]  | [email protected] 
             |              |              |
Square       | Square       | Square       | Square      
[email protected]    | [email protected]    | [email protected]    | [email protected]    

Das Problem

Am Ende stehen mir 24 generierte Bilder pro Bild zur Verfügung, was eine enorme Menge generierter Daten darstellt. Zwei Drittel dieser Daten werden niemals verwendet (die beiden anderen Ausrichtungen), und ich würde diese gerne entfernen. add_image_size() berücksichtigt die Bildorientierung nicht.

Gibt es eine Möglichkeit, nur die Bilder für die Ausrichtung des Bildes zu generieren?


Aktualisieren

TL; DR: Ich habe vielleicht eine Lösung gefunden, Code ist unten, weitere Tests morgen.

Ok, ich bin heute tief in den Wordpress Trac eingetaucht, und ich glaube, ich habe es verstanden.

Es ist schwer, die Generierung der Funktion add_image_size() zu ändern, daher habe ich den Hook wp_generate_attachment_metadata gewählt.

Die Bilder werden in der Funktion wp_generate_attachment_metadata() generiert. Es ist schwierig, die Funktion zu ändern, da der passende wp_generate_attachment_metadata-Hook stattfindet, nachdem die Bilder generiert wurden.

Trotzdem war dies der beste Haken, den ich für diesen Zweck gefunden habe. Ich habe beschlossen, meine eigenen Kopien des Originalbildes in der Größe zu erstellen (WP_Image_Editor hat das ziemlich einfach gemacht) und die neu erzeugten Bilder in die Metadaten des Originalbildes aufzunehmen.

Bisher sieht das ziemlich gut aus, außer dass der Fortschrittsbalken auf 100% bleibt, bis die Bilder verarbeitet wurden. Dies kann ein Problem sein, wenn Benutzer die Seite verlassen, bevor alle Bilder verarbeitet wurden. Das zweite Problem war, dass die benutzerdefinierten generierten Bilder nicht gelöscht werden, wenn ich den Anhang lösche. Dies liegt an der Funktion get_intermediate_image_sizes(), mit der nach Bildgrößen gesucht wird, die von add_image_size() hinzugefügt wurden. Ich habe den Haken intermediate_image_sizes gefunden und möchte versuchen, morgen alle möglichen Bildgrößen hinzuzufügen. In der Zwischenzeit habe ich eine schnelle Lösung, die den Haken delete_attachment verwendet.

Ich werde morgen weitere Tests durchführen und diesen Beitrag aktualisieren.

Hier ist mein Code soweit:

/**
 * 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

Hier ist meine Arbeitslösung. Der Code ist dokumentiert, daher sollte klar sein, was jede Funktion tut.

Ich verwende den wp_generate_attachment_metadata-Filter so ziemlich, um die benötigten Bilder zu erstellen, nachdem das Bild hochgeladen wurde.

Die generierten Bilder werden ebenso wie alle anderen Zwischenbildgrößen in den Metadaten aufgelistet. Auf diese Weise können Sie so gut wie mit jeder anderen Bildgröße arbeiten.

Ein weiterer wichtiger Teil ist die Verwendung des Filters delete_attachment, um die generierten Bilder zu löschen.

// ==========================
// 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