Skript zum auslesen der Hauptfarbe eines Bildes / Allowed memory size of 33554432 bytes exhausted

Ich möchte gerne aus einem Bild (Cover) die Hauptfarbe berechnen und daraus dann einen CSS Gradienten erstellen.

Probiert vom Ansatz habe ich das mit

<?php

// URL des Albumcovers
$cover_url = 'https://i.scdn.co/image/ab67616d0000b273bacc7255fe653f1ae7cd2bb9'; // Beispiel-URL

// Herunterladen des Albumcovers
$cover_data = file_get_contents($cover_url);

// Pfad zum temporären Bild
$temp_cover_path = '/tmp/cover.jpg'; // Stellen Sie sicher, dass das Verzeichnis beschreibbar ist

// Speichern des heruntergeladenen Covers in einer temporären Datei
file_put_contents($temp_cover_path, $cover_data);

// Funktion zur Extraktion der Hauptfarbe aus einem Bild mithilfe der GD-Bibliothek
function getMainColor($imagePath) {
    $image = imagecreatefromjpeg($imagePath);
    $imageWidth = imagesx($image);
    $imageHeight = imagesy($image);
    $colors = [];

    // Durchlaufen Sie das Bild und erfassen Sie die Farben
    for ($x = 0; $x < $imageWidth; $x++) {
        for ($y = 0; $y < $imageHeight; $y++) {
            $pixelColor = imagecolorat($image, $x, $y);
            $rgb = imagecolorsforindex($image, $pixelColor);
            $colors[] = [$rgb['red'], $rgb['green'], $rgb['blue']];
        }
    }

    // Berechnen Sie den Durchschnitt der Farben
    $totalColors = count($colors);
    $redSum = $greenSum = $blueSum = 0;

    foreach ($colors as $color) {
        $redSum += $color[0];
        $greenSum += $color[1];
        $blueSum += $color[2];
    }

    $averageRed = $redSum / $totalColors;
    $averageGreen = $greenSum / $totalColors;
    $averageBlue = $blueSum / $totalColors;

    return [$averageRed, $averageGreen, $averageBlue];
}

// Hauptfarbe aus dem Coverbild extrahieren
$mainColor = getMainColor($temp_cover_path);

// CSS-Gradienten generieren
$cssGradient = "linear-gradient(to bottom, rgb($mainColor[0],$mainColor[1],$mainColor[2]), #ffffff)";

// CSS-Gradienten ausgeben
$css = '<style>
body { background: ' . $cssGradient . '; }
</style>';
SetValue(44053, $css);

Beim Ausführen des Skripts erhalte ich eine Meldung:
Fatal error: Allowed memory size of 33554432 bytes exhausted (tried to allocate 4096 bytes) in /mnt/data/symcon/scripts/27314.ips.php on line 27

Meine Frage wäre nun was kann ich machen, dass es nicht zu dieser Fehlermeldung kommt?
Beziehungsweise hat jemand einen anderen Ansatz bzw. ein funktionierendes Skript in IP-Symcon das die Hauptfarbe aus einem Bild errechnet?

Wenn $colors zu viel Speicher nimmt, warum berechnest du die Summen nicht gleich in der Schleife wo das Bild durchgegangen wird.

Und das Bild musst du auch nicht auf Platte speichern, imagecreatefromjpeg kann direkt ein Bild per http laden.
Michael

1 „Gefällt mir“

Danke für den Hinweis, ich habe jetzt mal das Skript angepasst und die Samplerate reduziert, ist dann zwar weniger genau, aber es erzeugt keine Fehlermeldung mehr.

Auch dafür Danke, habe ich angepasst.

Das Skript ohne Fehlermeldung sieht jetzt so aus:

<?php

// URL des Albumcovers
$cover_url = 'https://i.scdn.co/image/ab67616d0000b273bacc7255fe653f1ae7cd2bb9'; // Beispiel-URL

function getMainColor($imagePath, $sampleRate = 5) {
    $image = imagecreatefromjpeg($imagePath);
    $imageWidth = imagesx($image);
    $imageHeight = imagesy($image);
    $colors = [];

    // Durchläuft das Bild und erfasst die Farben in Intervallen
    for ($x = 0; $x < $imageWidth; $x += $sampleRate) {
        for ($y = 0; $y < $imageHeight; $y += $sampleRate) {
            $pixelColor = imagecolorat($image, $x, $y);
            $rgb = imagecolorsforindex($image, $pixelColor);
            $colors[] = [$rgb['red'], $rgb['green'], $rgb['blue']];
        }
    }

    // Berechnet den Durchschnitt der Farben
    $totalColors = count($colors);
    $redSum = $greenSum = $blueSum = 0;

    foreach ($colors as $color) {
        $redSum += $color[0];
        $greenSum += $color[1];
        $blueSum += $color[2];
    }

    $averageRed = $redSum / $totalColors;
    $averageGreen = $greenSum / $totalColors;
    $averageBlue = $blueSum / $totalColors;

    return [$averageRed, $averageGreen, $averageBlue];
}


// Hauptfarbe aus dem Coverbild extrahieren
$mainColor = getMainColor($cover_url);

// CSS-Gradienten generieren
$cssGradient = "linear-gradient(to bottom, rgb($mainColor[0],$mainColor[1],$mainColor[2]), #ffffff)";

// CSS-Gradienten ausgeben
$css = '<style>
body { background: ' . $cssGradient . '; }
</style>';
SetValue(44053, $css);

Was machst du damit?

Ich generiere mir passend zu einem Spotify Cover oder auch Sonos Cover einen passenden Hintergrund zur Anzeige, genauso wie das die Spotify App selber auch macht. Der Unterschied ist nur, wenn Spotify selber Video Content vorliegt für das Lied, dann zeigt es den Videocontent in der Spotify App an.

2 „Gefällt mir“