1

Seems like I'm having problems using the streams which are piped to a process when using the proc_open() php function.

The process I'm starting is simply the convert ImageMagick utility to compose 3 images on top of each other. When only 1 input stream is used (STDIN) and a variable is dumped into that stream the convert program works fine and returns its output which can be stored in a variable like so:

$cmd = BIN_PATH.DIRECTORY_SEPARATOR.'convert ';
$cmd .= ' -size SOMESIZE ';
$cmd .= ' -background black ';
$cmd .= ' -fill white ';
$cmd .= ' -stroke none ';
$cmd .= ' -gravity center ';
$cmd .= ' -trim ';
$cmd .= ' -interline-spacing SOMELINEHEIGHT ';
$cmd .= ' -font SOMEFONT ';
$cmd .= ' label:"SOMETEXT" ';
$cmd .= ' miff:- ';
$ctext_opacity = shell_exec($cmd);

First I run the convert and store the output in the $ctext_opacity variable. Then the next command is called through proc_open() and the $ctext_opacity variable is piped trough the STDIN and used as an input image:

$cmd = BIN_PATH.DIRECTORY_SEPARATOR.'convert ';
$cmd .= '-size SOMESIZE ';
$cmd .= ' xc:\'rgb(230, 225, 50)\' ';
$cmd .= ' -gravity center ';
$cmd .= ' - '; // ImageMagick uses dash(-) for STDIN
$cmd .= ' -alpha Off ';
$cmd .= ' -compose CopyOpacity ';
$cmd .= ' -composite ';
$cmd .= ' -trim ';
$cmd .= ' miff:- ';
$chighlight = '';
$descriptorspec = array(
    0 => array("pipe", "r"),
    1 => array("pipe", "w")
);
$process = proc_open($cmd, $descriptorspec, $pipes);

if (is_resource($process)) {
    fwrite($pipes[0], $ctext_opacity);
    fclose($pipes[0]);

    while (!feof($pipes[1])) {
      $chighlight .= fgets($pipes[1]); // HERE WE FEED THE OUTPUT OF "CONVERT" TO    $chighlight
    }

    //echo $chighlight; die();
    fclose($pipes[1]);

    $return_value = proc_close($process);
}

The above command is called 3 times and 3 separate images are generated and stored in 3 variables. The next command is supposed to accept those 3 variables as input images (the ImageMagic syntax specifies the alternative io streams like fd:N where N is the number of the stream which I spawn through proc_open()). However I seem to be writing to the input streams or reading from the STDOUT incorrectly which results most probably in unflushed output from the process which causes it to hang without terminating.

$cmd = BIN_PATH.DIRECTORY_SEPARATOR.'convert ';
$cmd .= ' -size SOMESIZE ';
$cmd .= ' xc:transparent ';
$cmd .= ' -gravity center ';
$cmd .= ' - -geometry -2-2 -composite ';
$cmd .= ' fd:3 -geometry +2+2 -composite ';
$cmd .= ' fd:4 -composite ';
$cmd .= 'png:- ';

$descriptorspec = array(
    0 => array("pipe", "r"),
    1 => array("pipe", "w"),
    2 => array("pipe", "a"),
    3 => array("pipe", "r"),
    4 => array("pipe", "r")
);
$process = proc_open($cmd, $descriptorspec, $pipes);
if (is_resource($process)) {
    $read = null;
    $rd = array($pipes[1]);
    $write = array($pipes[0], $pipes[3], $pipes[4]);
    $wt = array($pipes[0], $pipes[3], $pipes[4]);
    $im_args = array($cshade, $chighlight, $ctext);
    $except = null;
    $readTimeout = 1;
    $ctext_deboss = '';

    $numchanged = stream_select($read, $write, $except, $readTimeout);
    foreach($write as $w) {
        $key = array_search($w, $wt);
        fwrite($wt[$key], $im_args[$key]);
        fclose($wt[$key]);

        $read = array($pipes[1]);
        $rd = array($pipes[1]);
        $write = null;
        $except = null;
        $readTimeout = 1;
        $ctext_deboss = '';

        $numchanged = stream_select($read, $write, $except, $readTimeout);
        foreach($read as $r) {
            while (!feof($r)) {
                $ctext_deboss .= fgets($pipes[1]);
            }
        }
        fclose($pipes[1]);

        $return_value = proc_close($process);
        echo $ctext_deboss; die();
    }
}

I can't seem to transfer the 3 & 4 pipes' contents as convert throws an error with empty/incorrect data

LU RD
  • 34,438
  • 5
  • 88
  • 296
CodeFan
  • 89
  • 1
  • 10

1 Answers1

1

The solution I settled down on was to concatenate the 3 generated images in one php variable. So each image output is concatenated to the next. Later when proc_open() is called assign only STDIN for the convert input stream (which will hold the input files data, that is our concatenated images var). The format I'm using is png and it does seem to work fine with stacked images like that. Each time you provide png:- in the convert command for input the next image will be pulled and used as input. That way you can provide the image data for all 3 images from a single variable.

The solution is just an alternative to the numbered file descriptors fd:N which is documented to be possible in Imagemagick. It does accomplish the task but the question why the extra input pipes I set up with proc_open() and provide to Imagemagick convert don't work.

         $khh = BIN_PATH.DIRECTORY_SEPARATOR.'convert ';
         $khh .= '                  -size '.$imageSize.' ';
         $khh .= '                  xc:\'rgb(230, 225, 50)\' ';
         $khh .= '                  -gravity center ';
         $khh .= '                  - ';
         $khh .= '                  -alpha Off ';
         $khh .= '                  -compose CopyOpacity ';
         $khh .= '                  -composite ';
         $khh .= '                  -trim ';
                    $khh .= '                  png:- ';

        $chighlight = '';
         $descriptorspec = array(
               0 => array("pipe", "r"),
               1 => array("pipe", "w")
         );
         $process = proc_open($khh, $descriptorspec, $pipes);

         if (is_resource($process)) {
            fwrite($pipes[0], $ctext_opacity);
            fclose($pipes[0]);

            while (!feof($pipes[1])) {
               $chighlight .= fgets($pipes[1]);
            }

            fclose($pipes[1]);

            $return_value = proc_close($process);
         }

....................................................................................

         $khh = BIN_PATH.DIRECTORY_SEPARATOR.'convert ';
         $khh .= '                  -size '.$imageSize.' ';
         $khh .= '                  xc:'.$fontColor.' ';
         $khh .= '                  -gravity center ';
         $khh .= '                  - ';
         $khh .= '                  -alpha Off ';
         $khh .= '                  -compose CopyOpacity ';
         $khh .= '                  -composite ';
         $khh .= '                  -trim ';
         if($_GET['ctr']==='3') {
             $khh .= '                  png:- ';
         } else {
             $khh .= '                  png:- ';
         }
         $ctext = '';
         $descriptorspec = array(
               0 => array("pipe", "r"),
               1 => array("pipe", "w")
         );
         $process = proc_open($khh, $descriptorspec, $pipes);

         if (is_resource($process)) {
            fwrite($pipes[0], $ctext_opacity);
            fclose($pipes[0]);

            while (!feof($pipes[1])) {
               $ctext .= fgets($pipes[1]);
            }

            fclose($pipes[1]);

            $return_value = proc_close($process);
         }

....................................................................................

         $khh = BIN_PATH.DIRECTORY_SEPARATOR.'convert ';
         $khh .= '                  -size '.$imageSize.' ';
         $khh .= '                  xc:\'rgb(50, 85, 20)\' ';
         $khh .= '                  -gravity center ';
         $khh .= '                  - ';
         $khh .= '                  -alpha Off ';
         $khh .= '                  -compose CopyOpacity ';
         $khh .= '                  -composite ';
         $khh .= '                  -trim ';
          $khh .= '                  png:- ';
         $cshade = '';
         $descriptorspec = array(
               0 => array("pipe", "r"),
               1 => array("pipe", "w")
         );
         $process = proc_open($khh, $descriptorspec, $pipes);

         if (is_resource($process)) {
            fwrite($pipes[0], $ctext_opacity);
            fclose($pipes[0]);

            while (!feof($pipes[1])) {
               $cshade .= fgets($pipes[1]);
            }

            fclose($pipes[1]);

            $return_value = proc_close($process);
         }

....................................................................................

         $khh = BIN_PATH.DIRECTORY_SEPARATOR.'convert ';
         $khh .= '                  -size '.$sizeX.'x'.$sizeY;
         $khh .= '                  xc:transparent ';
         $khh .= '                  -gravity center ';
         $khh .= '                  png:- -geometry -'.$i.'-'.$i.' -composite ';
         $khh .= '                  png:- -geometry +'.$i.'+'.$i.' -composite ';
         $khh .= '                  png:- -composite ';
              $khh .= '                  png:- ';

         $ctext_deboss = '';
          $descriptorspec = array(
               0 => array("pipe", "r"),
               1 => array("pipe", "w")
         );
         $process = proc_open($khh, $descriptorspec, $pipes);

         if (is_resource($process)) {
            fwrite($pipes[0], $cshade.$chighlight.$ctext);
            fclose($pipes[0]);

            while (!feof($pipes[1])) {
               $ctext_deboss .= fgets($pipes[1]);
            }

            fclose($pipes[1]);

            $return_value = proc_close($process);
         }

....................................................................................

CodeFan
  • 89
  • 1
  • 10