Skip to content
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,10 @@ public function get_dominant_color() {
$this->image->resizeImage( 1, 1, Imagick::FILTER_LANCZOS, 1 );
$pixel = $this->image->getImagePixelColor( 0, 0 );
$color = $pixel->getColor();
$hex = dominant_color_rgb_to_hex( $color['r'], $color['g'], $color['b'] );
// Cast to int: ImagickPixel::getColor() may return floats depending on
// ImageMagick/Imagick configuration, which would break the int contract
// of dominant_color_rgb_to_hex() under strict_types.
$hex = dominant_color_rgb_to_hex( (int) $color['r'], (int) $color['g'], (int) $color['b'] );
if ( null === $hex ) {
return new WP_Error( 'image_editor_dominant_color_error', __( 'Dominant color detection failed.', 'dominant-color-images' ) );
}
Expand Down
57 changes: 30 additions & 27 deletions plugins/dominant-color-images/helper.php
Original file line number Diff line number Diff line change
Expand Up @@ -90,13 +90,9 @@ function dominant_color_get_dominant_color_data( int $attachment_id ) {
}

$file = dominant_color_get_attachment_file_path( $attachment_id );
if ( false === $file ) {
$file = get_attached_file( $attachment_id );
}
if ( false === $file ) {
return new WP_Error( 'no_image_found', __( 'Unable to load image.', 'dominant-color-images' ) );
}
add_filter( 'wp_image_editors', 'dominant_color_set_image_editors' );

/**
* Editor.
Expand All @@ -113,7 +109,6 @@ function dominant_color_get_dominant_color_data( int $attachment_id ) {
),
)
);
remove_filter( 'wp_image_editors', 'dominant_color_set_image_editors' );

if ( is_wp_error( $editor ) ) {
return $editor;
Expand All @@ -140,6 +135,28 @@ function dominant_color_get_dominant_color_data( int $attachment_id ) {
return $dominant_color_data;
}

/**
* Retrieves attachment metadata for an image attachment.
*
* @since n.e.x.t
*
* @param int $attachment_id Attachment ID.
* @return array<string, mixed>|null Attachment metadata array, or null if not an image or metadata unavailable.
*/
function dominant_color_get_attachment_metadata( int $attachment_id ): ?array {

if ( ! wp_attachment_is_image( $attachment_id ) ) {
return null;
}

$image_meta = wp_get_attachment_metadata( $attachment_id );
if ( ! is_array( $image_meta ) ) {
return null;
}

return $image_meta;
}

/**
* Gets file path of image based on size.
*
Expand All @@ -150,21 +167,17 @@ function dominant_color_get_dominant_color_data( int $attachment_id ) {
* @return false|string Path to an image or false if not found.
*/
function dominant_color_get_attachment_file_path( int $attachment_id, string $size = 'medium' ) {
$imagedata = wp_get_attachment_metadata( $attachment_id );
if ( ! is_array( $imagedata ) ) {
return false;
}

if ( ! isset( $imagedata['sizes'][ $size ] ) ) {
$filepath = get_attached_file( $attachment_id );
if ( false === $filepath ) {
return false;
}

$file = get_attached_file( $attachment_id );
if ( false === $file ) {
return false;
}
$image_meta = dominant_color_get_attachment_metadata( $attachment_id );

$filepath = str_replace( wp_basename( $file ), $imagedata['sizes'][ $size ]['file'], $file );
if ( isset( $image_meta['sizes'][ $size ] ) ) {
$filepath = str_replace( wp_basename( $filepath ), $image_meta['sizes'][ $size ]['file'], $filepath );
}

return $filepath;
}
Expand All @@ -178,13 +191,7 @@ function dominant_color_get_attachment_file_path( int $attachment_id, string $si
* @return string|null Hex value of dominant color or null if not set.
Comment thread
nickchomey marked this conversation as resolved.
Outdated
*/
function dominant_color_get_dominant_color( int $attachment_id ): ?string {
if ( ! wp_attachment_is_image( $attachment_id ) ) {
return null;
}
$image_meta = wp_get_attachment_metadata( $attachment_id );
if ( ! is_array( $image_meta ) ) {
return null;
}
$image_meta = dominant_color_get_attachment_metadata( $attachment_id );

if ( ! isset( $image_meta['dominant_color'] ) ) {
Comment thread
nickchomey marked this conversation as resolved.
Outdated
return null;
Expand All @@ -202,10 +209,7 @@ function dominant_color_get_dominant_color( int $attachment_id ): ?string {
* @return bool|null Whether the image has transparency, or null if not set.
*/
function dominant_color_has_transparency( int $attachment_id ): ?bool {
$image_meta = wp_get_attachment_metadata( $attachment_id );
if ( ! is_array( $image_meta ) ) {
return null;
}
$image_meta = dominant_color_get_attachment_metadata( $attachment_id );

if ( ! isset( $image_meta['has_transparency'] ) ) {
return null;
Expand All @@ -214,7 +218,6 @@ function dominant_color_has_transparency( int $attachment_id ): ?bool {
return $image_meta['has_transparency'];
Comment thread
nickchomey marked this conversation as resolved.
Outdated
}


/**
* Gets hex color from RGB.
*
Expand Down
18 changes: 18 additions & 0 deletions plugins/dominant-color-images/load.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,22 @@

require_once __DIR__ . '/helper.php';
require_once __DIR__ . '/hooks.php';

add_filter(
'wp_image_editors',
static function ( array $editors ): array {
Comment thread
nickchomey marked this conversation as resolved.
Outdated
// Ensure core editor classes are loaded before delegating, since this
// filter can run early (e.g. during wp_image_editor_supports()).
if ( ! class_exists( 'WP_Image_Editor_GD' ) ) {
require_once ABSPATH . WPINC . '/class-wp-image-editor-gd.php';
}
if ( ! class_exists( 'WP_Image_Editor_Imagick' ) ) {
require_once ABSPATH . WPINC . '/class-wp-image-editor-imagick.php';
}

return dominant_color_set_image_editors( $editors );
},
999,
1
);
Comment thread
nickchomey marked this conversation as resolved.
Outdated
// @codeCoverageIgnoreEnd
42 changes: 28 additions & 14 deletions plugins/dominant-color-images/tests/data/class-testcase.php
Original file line number Diff line number Diff line change
Expand Up @@ -157,10 +157,10 @@ public function provider_get_dominant_color_invalid_images(): array {
public function provider_get_dominant_color_none_images(): array {
return array(
'pdf' => array(
'files_path' => TESTS_PLUGIN_DIR . '/tests/data/images/wordpress-gsoc-flyer.pdf',
'image_path' => TESTS_PLUGIN_DIR . '/tests/data/images/wordpress-gsoc-flyer.pdf',
),
'mp4' => array(
'files_path' => TESTS_PLUGIN_DIR . '/tests/data/images/small-video.mp4',
'image_path' => TESTS_PLUGIN_DIR . '/tests/data/images/small-video.mp4',
),
);
}
Expand All @@ -182,7 +182,6 @@ public function test_get_dominant_color_valid( string $image_path, array $expect
}

$attachment_id = self::factory()->attachment->create_upload_object( $image_path );
wp_maybe_generate_attachment_metadata( get_post( $attachment_id ) );

$dominant_color_data = dominant_color_get_dominant_color_data( $attachment_id );

Expand All @@ -208,47 +207,62 @@ public function test_get_dominant_color_invalid( string $image_path ): void {
if ( ! wp_image_editor_supports( array( 'mime_type' => $mime_type ) ) ) {
$this->markTestSkipped( "Mime type $mime_type is not supported." );
}
$attachment_id = self::factory()->attachment->create_upload_object( $image_path );
wp_maybe_generate_attachment_metadata( get_post( $attachment_id ) );
$attachment_id = self::factory()->attachment->create(
array(
'post_mime_type' => $mime_type,
)
);

$dominant_color_data = dominant_color_get_dominant_color_data( $attachment_id );

$this->assertWPError( $dominant_color_data );
$this->assertStringContainsString( 'unsupported_attachment_type', $dominant_color_data->get_error_code() );
$this->assertSame( 'unsupported_attachment_type', $dominant_color_data->get_error_code() );
}

/**
* Test the function returns a WP_Error object for unsupported mime types.
* Tests dominant_color_get_dominant_color_data() returns a WP_Error when the
* dominant_color_supported_mime_types filter returns an empty array.
*
* @covers dominant_color_get_dominant_color_data
*/
public function test_get_dominant_color_data_unsupported_mime_type(): void {
add_filter( 'dominant_color_supported_mime_types', '__return_empty_array' );
$image_path = TESTS_PLUGIN_DIR . '/tests/data/images/red.jpg';

$attachment_id = self::factory()->attachment->create_upload_object( $image_path );
wp_maybe_generate_attachment_metadata( get_post( $attachment_id ) );
$attachment_id = self::factory()->attachment->create(
array(
'post_mime_type' => 'image/jpeg',
)
);

$dominant_color_data = dominant_color_get_dominant_color_data( $attachment_id );

$this->assertWPError( $dominant_color_data );
$this->assertStringContainsString( 'unsupported_attachment_type', $dominant_color_data->get_error_code() );
$this->assertSame( 'unsupported_attachment_type', $dominant_color_data->get_error_code() );
}

/**
* Test if the function returns the correct color.
* Tests dominant_color_get_dominant_color_data() returns a WP_Error for non-image file types.
*
* @covers Dominant_Color_Image_Editor_GD::get_dominant_color
* @covers Dominant_Color_Image_Editor_Imagick::get_dominant_color
*
* @dataProvider provider_get_dominant_color_none_images
*/
public function test_get_dominant_color_none_images( string $image_path ): void {
$attachment_id = self::factory()->attachment->create_upload_object( $image_path );
wp_maybe_generate_attachment_metadata( get_post( $attachment_id ) );
$mime_type = wp_check_filetype( $image_path )['type'];
if ( false === $mime_type ) {
$this->markTestSkipped( 'Mime type is not supported.' );
}

$attachment_id = self::factory()->attachment->create(
array(
'post_mime_type' => $mime_type,
)
);

$dominant_color_data = dominant_color_get_dominant_color_data( $attachment_id );

$this->assertWPError( $dominant_color_data );
$this->assertSame( 'unsupported_attachment_type', $dominant_color_data->get_error_code() );
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,14 @@
* Tests for Image Placeholders plugin.
*
* @package dominant-color-images
* @noinspection PhpComposerExtensionStubsInspection
*/

use Dominant_Color_Images\Tests\TestCase;

/**
* @coversDefaultClass Dominant_Color_Image_Editor_GD
*/
class Test_Dominant_Color_Image_Editor_GD extends TestCase {

/**
Expand All @@ -19,6 +23,11 @@ public function set_up(): void {
$this->markTestSkipped( 'The GD PHP extension is not loaded.' );
}

// Ensure the GD editor is registered. It doesn't seem to be by the time this runs.
require_once ABSPATH . WPINC . '/class-wp-image-editor.php';
require_once ABSPATH . WPINC . '/class-wp-image-editor-gd.php';
require_once __DIR__ . '/../class-dominant-color-image-editor-gd.php';

add_filter(
'wp_image_editors',
static function ( array $editors ): array {
Expand All @@ -31,4 +40,93 @@ static function ( $editor ): bool {
}
);
}

/**
* @covers ::get_dominant_color
*/
public function test_invalid_image_type(): void {
$editor = new Dominant_Color_Image_Editor_GD( '/invalid/type' );
$result = $editor->get_dominant_color();
$this->assertWPError( $result );
$this->assertSame( 'image_editor_dominant_color_error_no_image', $result->get_error_code() );
}

/**
* @covers ::get_dominant_color
*/
public function test_get_dominant_color_no_image(): void {
$editor = new Dominant_Color_Image_Editor_GD( null );
$result = $editor->get_dominant_color();

$this->assertWPError( $result );
$this->assertSame( 'image_editor_dominant_color_error_no_image', $result->get_error_code() );
}

/**
* @covers ::has_transparency
*/
public function test_has_transparency_no_image(): void {
$editor = new Dominant_Color_Image_Editor_GD( null );
$result = $editor->has_transparency();

$this->assertWPError( $result );
$this->assertSame( 'image_editor_has_transparency_error_no_image', $result->get_error_code() );
}

/**
* @covers ::get_dominant_color
*/
public function test_get_dominant_color_success(): void {
$im = imagecreatetruecolor( 1, 1 );
$red = imagecolorallocate( $im, 255, 0, 0 );
imagefill( $im, 0, 0, $red );

$editor = new Dominant_Color_Image_Editor_GD( null );
$reflection = new ReflectionClass( $editor );
$property = $reflection->getProperty( 'image' );
$property->setAccessible( true );
$property->setValue( $editor, $im );

$result = $editor->get_dominant_color();

$this->assertSame( 'ff0000', $result );
}

/**
* @covers ::has_transparency
*/
public function test_has_no_transparency(): void {
$im = imagecreatetruecolor( 1, 1 );
$red = imagecolorallocate( $im, 255, 0, 0 );
imagefill( $im, 0, 0, $red );

$editor = new Dominant_Color_Image_Editor_GD( null );
$reflection = new ReflectionClass( $editor );
$property = $reflection->getProperty( 'image' );
$property->setAccessible( true );
$property->setValue( $editor, $im );

$result = $editor->has_transparency();

$this->assertFalse( $result );
}

/**
* @covers ::has_transparency
*/
public function test_has_transparency_with_transparency(): void {
$im = imagecreatetruecolor( 1, 1 );
$alpha_color = imagecolorallocatealpha( $im, 255, 0, 0, 64 );
imagefill( $im, 0, 0, $alpha_color );

$editor = new Dominant_Color_Image_Editor_GD( null );
$reflection = new ReflectionClass( $editor );
$property = $reflection->getProperty( 'image' );
$property->setAccessible( true );
$property->setValue( $editor, $im );

$result = $editor->has_transparency();

$this->assertTrue( $result );
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ public function set_up(): void {
$this->markTestSkipped( 'The Imagick PHP extension is not loaded.' );
}

// Ensure the Imagick editor is registered, even though it seems to be by the time this runs.
require_once ABSPATH . WPINC . '/class-wp-image-editor.php';
require_once ABSPATH . WPINC . '/class-wp-image-editor-imagick.php';
require_once __DIR__ . '/../class-dominant-color-image-editor-imagick.php';

add_filter(
'wp_image_editors',
static function ( array $editors ): array {
Expand Down Expand Up @@ -147,7 +152,7 @@ public function test_get_dominant_color_success(): void {

$result = $editor->get_dominant_color();

$this->assertEquals( 'ff0000', $result );
$this->assertSame( 'ff0000', $result );
}

/**
Expand Down
Loading
Loading