Halftone effect using IMagick API

IMagick is a native PHP extension to create and modify images using the ImageMagick API. ImageMagick Studio LLC did not write nor does it maintain the IMagick extension, however, IMagick users are welcome to discuss the extension here.
Post Reply
owo
Posts: 4
Joined: 2018-11-19T04:11:01-07:00
Authentication code: 1152

Halftone effect using IMagick API

Post by owo »

I am trying to replicate a color halftone effect using the API.

I'm using this command I found on another post on this forum for reference and trying to translate it to API calls but I am not very familiar with the IM command line and am getting stuck.

Code: Select all

  convert ~/im/images/logo.gif -set option:distort:viewport '%wx%h+0+0' \
      -colorspace CMYK -separate null: \
      \( -size 2x2 xc: \( +clone -negate \) \
            +append \( +clone -negate \) -append \) \
      -virtual-pixel tile -filter gaussian \
      \( +clone -distort SRT 60 \) +swap \
      \( +clone -distort SRT 30 \) +swap \
      \( +clone -distort SRT 45 \) +swap \
      \( +clone -distort SRT 0 \)  +swap +delete \
      -compose Overlay -layers composite \
      -set colorspace CMYK -combine -colorspace RGB \
      logo_cmyk_halftone_2.png
So far:

Code: Select all

$im = new Imagick();
$im->readImage('logo.gif');
$im->setImageArtifact('option:distort:viewport', '%wx%h+0+0');
$im->transformImageColorspace(\Imagick::COLORSPACE_CMYK);

$imx = new Imagick();
$imx->setColorspace(\Imagick::COLORSPACE_CMYK);
$imx->newPseudoImage(2, 2, 'xc:'); //-size 2x2 xc:
$imx->addImage($imx->getImage()); //+clone
$imx->negateImage(false); //-negate
$imx->appendImages(false); //+append
$imx->addImage($imx->getImage()); //+clone
$imx->negateImage(false); //-negate
$imx->appendImages(true); //-append
$imx
$imx->setImageVirtualPixelMethod(imagick::VIRTUALPIXELMETHOD_TILE);
$imx->setOption('filter:filter', 'Gaussian');

$imf = new Imagick();
$imf->newImage($im->getImageWidth(), $im->getImageHeight(), 'none');

$imcy = clone $im;
$imcy->separateImageChannel(imagick::CHANNEL_CYAN);

$imf->addImage(clone $imx);
//$imf->setImageExtent($im->getImageWidth(), $im->getImageHeight());
$imf->distortImage(imagick::DISTORTION_SCALEROTATETRANSLATE, array(60), true);
//$imf->compositeImage($imcy, imagick::COMPOSITE_OVERLAY, 0, 0);


$im->nextImage();
$im->separateImageChannel(imagick::CHANNEL_MAGENTA);

$imc = clone $imx;
$imc->setImageVirtualPixelMethod(imagick::VIRTUALPIXELMETHOD_TILE);
$imc->distortImage(imagick::DISTORTION_SCALEROTATETRANSLATE, array(30), true);
$imc->compositeImage($im, imagick::COMPOSITE_OVERLAY, 0, 0);
$im->setImage($imc);

$im->nextImage();
$im->separateImageChannel(imagick::CHANNEL_YELLOW);

$imc = clone $imx;
$imc->setImageVirtualPixelMethod(imagick::VIRTUALPIXELMETHOD_TILE);
$imc->distortImage(imagick::DISTORTION_SCALEROTATETRANSLATE, array(45), true);
$imc->compositeImage($im, imagick::COMPOSITE_OVERLAY, 0, 0);
$im->setImage($imc);

$im->nextImage();
$im->separateImageChannel(imagick::CHANNEL_BLACK);

$imc = clone $imx;
$imc->setImageVirtualPixelMethod(imagick::VIRTUALPIXELMETHOD_TILE);
$imc->distortImage(imagick::DISTORTION_SCALEROTATETRANSLATE, array(0), true);
$imc->compositeImage($im, imagick::COMPOSITE_OVERLAY, 0, 0);
$im->setImage($imc);

$im->setColorspace(\Imagick::COLORSPACE_CMYK);
$im = $im->combineImages(imagick::CHANNEL_CYAN | imagick::CHANNEL_MAGENTA | imagick::CHANNEL_YELLOW | imagick::CHANNEL_BLACK);
$im->transformImageColorspace(Imagick::COLORSPACE_RGB);
$im->setFormat('png32');
echo $im;
What does "-separate null:" do - from what I understood supplying null: as an output file will junk the results so wouldn't this separate the channels then junk them? but of course it isn't doing that. How does the rest of the command receive the separated channels?

Are these channels split as CMYK or is it RGBK? I'm trying to replicate Photoshop's filter which I think uses CMYK.

And... once this works, how would I proceed to make the dots of varying sizes?

Thank you!
snibgo
Posts: 12159
Joined: 2010-01-23T23:01:33-07:00
Authentication code: 1151
Location: England, UK

Re: Halftone effect using IMagick API

Post by snibgo »

I don't use IMagick so can't help with that.

"-separate" and "null:" are two operations.

"-separate" takes each of its input images and creates one image for each input channel. Its input image is in the CMYK colorspace, so it makes four outputs.

"null:" is a pseudo-image. When an image is named with no operation, when this occurs at the end of the command this writes the image, otherwise it reads the image. So, here, "null:" reads the null image. This is used later in "-layers composite".
snibgo's IM pages: im.snibgo.com
owo
Posts: 4
Joined: 2018-11-19T04:11:01-07:00
Authentication code: 1152

Re: Halftone effect using IMagick API

Post by owo »

Would this be a correct understanding of it?

convert ~/im/images/logo.gif -set option:distort:viewport '%wx%h+0+0' \
-colorspace CMYK -separate

= There are 4 images on the image stack now, one for each of C M Y K.

null: \

= Use the null image as a delimiter

\( -size 2x2 xc: \( +clone -negate \) \
+append \( +clone -negate \) -append \) \

= Creates a 5th image: start with a 2x2 white image, copy that white image and negate to black and append them, then copy that and negate it again to form a checkerboard pattern

-virtual-pixel tile -filter gaussian \

= Sets a tile virtual pixel and gaussian filter on the following commands.

\( +clone -distort SRT 60 \) +swap \

= Copy the checkerboard image, rotate 60 degrees, then swap spaces so this is image 5 and the original checkerboard is image 6

\( +clone -distort SRT 30 \) +swap \

= Copy the checkerboard image, rotate 30 degrees, then swap spaces so this is image 6 and the original checkerboard is image 7

\( +clone -distort SRT 45 \) +swap \

= Copy the checkerboard image, rotate 45 degrees, then swap spaces so this is image 7 and the original checkerboard is image 8

\( +clone -distort SRT 0 \) +swap +delete \

= Copy the checkerboard image, rotate 0 degrees, then swap spaces so this is image 8 and the original checkerboard is image 9, then delete image 9

-compose Overlay -layers composite \

= Set the last 4 images as Overlay, then overlay them over the corresponding separated cmyk channels

-set colorspace CMYK -combine -colorspace RGB \

= Combine the 4 images

logo_cmyk_halftone_2.png

Code: Select all

$im = new Imagick();
$im->readImage('logo.gif');
$im->transformImageColorspace(\Imagick::COLORSPACE_CMYK);
$w = $im->getImageWidth();
$h = $im->getImageHeight();

$imx = new Imagick();
$imx->newPseudoImage(2, 2, 'xc:'); //-size 2x2 xc:
$imx->addImage(clone $imx); //+clone
$imx->negateImage(false); //-negate
$imx->resetIterator();
$imx = $imx->appendImages(false); //+append
$imx->addImage(clone $imx); //+clone
$imx->negateImage(false); //-negate
$imx->resetIterator();
$imx = $imx->appendImages(true); //-append

$channels = array(imagick::CHANNEL_CYAN => 60,
			imagick::CHANNEL_MAGENTA => 30,
			imagick::CHANNEL_YELLOW => 45,
			imagick::CHANNEL_BLACK => 0);
			
$imf = new Imagick();
$imf->setColorspace(\Imagick::COLORSPACE_CMYK);

foreach($channels as $channel => $degree){
	$tmp = clone $imx;
	
	$tmp->setImagePage($w, $h, 0, 0);
	$tmp->setOption('distort:viewport', "{$w}x{$h}");
	$tmp->setImageVirtualPixelMethod(imagick::VIRTUALPIXELMETHOD_TILE);
	$tmp->setOption('filter:filter', 'Gaussian');
	$tmp->distortImage(imagick::DISTORTION_SCALEROTATETRANSLATE, array(1, $degree), false);
	$tmp->setImageCompose(imagick::COMPOSITE_OVERLAY);
		
	$tmi = clone $im;
	$tmi->separateImageChannel($channel);
	$tmi->addImage($tmp);
	$tmi = $tmi->mergeImageLayers(Imagick::LAYERMETHOD_COMPOSITE);
	//$tmi->compositeImage($tmp, imagick::COMPOSITE_OVERLAY, 0, 0);
	//$tmi->setImageFormat('png'); die($tmi);
	$imf->addImage($tmi);
}


//var_dump($imf); die();
//$imf = $imf->mergeImageLayers(Imagick::LAYERMETHOD_FLATTEN);
$imf = $imf->combineImages(imagick::CHANNEL_ALL);
//var_dump($imf); die();
$imf->transformImageColorspace(Imagick::COLORSPACE_SRGB);
$imf->setImageFormat('png');
echo $imf;
snibgo
Posts: 12159
Joined: 2010-01-23T23:01:33-07:00
Authentication code: 1151
Location: England, UK

Re: Halftone effect using IMagick API

Post by snibgo »

A minor correction to your understanding: yes, "null:" will be used as a separator, but it is an image, the 5th in the list. So the checkerboard will be the 7th, etc.
snibgo's IM pages: im.snibgo.com
Post Reply