Losowe artefakty przy sklejaniu obrazów

0

Cześć,
Mam problem z Imagick w php. Podczas generowania obrazów powstają na nich artefakty.
W skrócie, jest tworzone płótno, na które są nakładane obrazki jeden obok drugiego. Po zapisie płótna. Widać na nim artefakty. Efekt ten jest losowy. Czasami pojawia się czarna linia na samej górze, a czasami szum przez środek obrazka. Po pierwszym przebiegu np obrazek 1_0 jest wygenerowany poprawnie, a po drugim już zawiera defekty.

// $files - list obiektów przechowująca ścieżkę do pliku obrazu
// $this->formName - plik wyjściowy obrazu
    private function generateImg($files)
    {
        $currentW = 0;
        $formImg = new Imagick();
        $formImg->newImage(450, 280, $this->pixel, 'png');
        $formImg->setImageAlphaChannel(Imagick::ALPHACHANNEL_ACTIVATE);
        $formImg->floodFillPaintImage('#FFFFFFFF', 10, '#FFFFFF', 0, 0, false);

        $index = 1;

        foreach ($files as $file) {
            echo '.';

            $phaseImg = new Imagick();

            echo "File:{$file->getPath()}\n";

            $phaseImg->readImage($file->getPath());
            $phaseImg->setImageAlphaChannel(Imagick::ALPHACHANNEL_ACTIVATE);
            $phaseImg->floodFillPaintImage('#FFFFFFFF', 10, '#FFFFFF', 0, 0, false);

            $formImg->compositeImage($phaseImg, Imagick::COMPOSITE_MATHEMATICS, $currentW, 0);
            $currentW += $phaseImg->getImageWidth();
            $phaseImg->writeImage("./sample/debug_{$this->formName}_{$index}.png");
            $phaseImg->clear();
            $phaseImg->destroy();

            $index++;
        }

        $path = "./out/{$this->formName}.png";
        $formImg->writeImage($path);

        $formImg->clear();
        $formImg->destroy();
        gc_collect_cycles();
        echo "\n";
    }

W załączniku przykład defektów.

Czy ktoś spotkał się z podobnym problemem i zna rozwiązanie?

PHP 7.3.2 x64 TS

image

image

image

1

Który Ci źle zapisuje: formImg czy phaseImg?

0

Z formImg.

2

a spróbuj zapisać tylko z jednym wstawionym obrazkiem bez pętli foreach i co wtedy?

0

Może za słabo to opisałem. metoda generateImg skleja mi obrazki w jeden.
Kiedy 1 raz wywołam tą metodę, to obrazek wychodzi dobry ale jak wywołam generateImg kilka razy (np jedno pod drugim) to zaczyna się losowo sypać.

1

ale kilka razy dla tych samych danych?

0

$files to lista poszczególnych plików, które mają zostać posklejane w jeden. W części przypadków pliki te się powtarzają. Obrazki te są tylko readonly i to na jednym wątku. Też myślałem że może coś innego mi w nich gmera podczas operacji na nich, ale wykluczyłem tą możliwość.

1

ale zawsze za pierwszym razem jest poprawnie? wywołujesz jedno wywołanie funkcji po drugim czy coś robisz pomiędzy tymi wywołaniami?

0

Tak, jedno po drugim.

1

jak zmieniasz {$this->formName} ?

0

przed wywołaniem generateImg jest przypisywana nowa nazwa

1

czyli jednak te wywołania nie są jeden po drugim ;)

0

no nie wprost

for($this->formName=0;$this->formName<count($a);$this->formName++){
 generateImg($a[$this->formName]);
}
0

No to spróbuj bez tego ;)
W sensie że naprawdę wywołaj kilka razy z tym samym parametrem, dokładnie tym samym.

0
$this->formName = 0;
generateImg($a[$this->formName]);
generateImg($a[$this->formName]); // (to nadpisuje poprzedni obrazek)

Zrobiłem taki test, po odpaleniu obrazek był poprawny. Jednak kilkukrotnie ponowiłem ten test i czasami obraz był poprawny a czasem z artefaktami.
Mam wrażenie, że coś jest nie tak albo z samym portem imagicka dla php i miesza w strumieniu danych, albo coś mam nie tak z kompem.
Jak będę miał chwile czasu to postawie OS na innym sprzęcie i spróbuje wykonać na nim testy.

0
hzmzp napisał(a):

zrób taki

$x= $a[$this->formName];
var_dump($x);
generateImg($x);
var_dump($x);
generateImg($x); 
0

Nie bardzo rozumiem po co?
Wyplute zostanie 2 razy to samo, czyli obiekty przechowujące składowe do budowy ścieżki, getPath() wypluwa string ze ścieżką.
Te obiekty są raz utworzone i nie są modyfikowane jeżeli o to chodzi.

0

Nie musisz używać:

$formImg->destroy();
# oraz
$phaseImg->destroy();

phaseImg możesz dać przed pętlę.

Najważniejsze:

$formImg->compositeImage($phaseImg, Imagick::COMPOSITE_MATHEMATICS, $currentW, 0);

Co to jest Imagick::COMPOSITE_MATHEMATICS? I skąd to masz?

0
malencki napisał(a):

Nie musisz używać:

$formImg->destroy();
# oraz
$phaseImg->destroy();

phaseImg możesz dać przed pętlę.

Najważniejsze:

$formImg->compositeImage($phaseImg, Imagick::COMPOSITE_MATHEMATICS, $currentW, 0);

Co to jest Imagick::COMPOSITE_MATHEMATICS? I skąd to masz?

  1. Zwalnianie pamięci po jej alokacji to dobry nawyk.
  2. Wynika z 1
  3. Example 1 z https://www.php.net/manual/en/imagick.compositeimage.php
1
hzmzp napisał(a):
malencki napisał(a):

Nie musisz używać:

$formImg->destroy();
# oraz
$phaseImg->destroy();

phaseImg możesz dać przed pętlę.

Najważniejsze:

$formImg->compositeImage($phaseImg, Imagick::COMPOSITE_MATHEMATICS, $currentW, 0);

Co to jest Imagick::COMPOSITE_MATHEMATICS? I skąd to masz?

  1. Zwalnianie pamięci po jej alokacji to dobry nawyk.
  2. Wynika z 1
  3. Example 1 z https://www.php.net/manual/en/imagick.compositeimage.php
  1. Nie, nie zwalniasz pamięci (w rozumieniu - zniszcz obiekt) :D Proponuję abyś przeczytał w dokumentacji. raz co robi destroy, a co robi clear.
  2. Patrz dokumentacja co robi clear i dlaczego nie jest potrzebne tworzenie na nowo obiektu.
  3. Coś mi się kojarzy, że taka wartość była w magicku. Ale została usnięta kilka lat temu?
    Ogólnie nie jestem pewien. Możliwe, że się mylę.
    Natomiast teraz masz https://www.php.net/manual/en/imagick.constants.php#imagick.constants.compositeop
    Nie ma tam tej wartości, proponuję Tobie, abyś zwyczajnie ją zmienił i sprawdził czy problem nadal występuje.
    Na przykład na imagick::COMPOSITE_ADD.

1 użytkowników online, w tym zalogowanych: 0, gości: 1