Imagick::steganoImage() Unable to show the watermark - imagick

I'm trying to use Imagick::steganoImage with an example image from wikimedia commons.
If I try to show the decoded image of the watermark, I always obtain the 1 pixel image you can see below, whatever image I choose as source.
Anyone may help me to understand why and how I can sort this out?
<?
header("Content-Type: image/png");
// Create a new imagick object
$image = new Imagick('https://upload.wikimedia.org/wikipedia/commons/thumb/1/16/Frostedbubble2.jpg/640px-Frostedbubble2.jpg');
$watermark = new Imagick('LABEL:Hello World!');
// The decoding process must "know" about the watermarks size, and starting
// pixel offset.
define('STEGANO_OFFSET', 64); // Secret offset
define('STEGANO_WIDTH', $watermark->getImageWidth());
define('STEGANO_HEIGHT', $watermark->getImageHeight());
$stegano = $image->steganoImage($watermark, STEGANO_OFFSET);
$stegano->writeImage('output.png');
$decoded = new Imagick();
$decoded->setSizeOffset(STEGANO_WIDTH, STEGANO_HEIGHT, STEGANO_OFFSET);
$decoded->readImage('STEGANO:output.png');
$decoded->writeImage('decoded.png');
// Show the output
$decoded->setImageFormat('png');
echo $decoded->getImageBlob();
?>
I tried also the code at this page https://www.geeksforgeeks.org/php-imagick-steganoimage-function/ and the geeksforgeeks image is shown correctly but the stegano image appear as totally black.
<?php
// Create a new imagick object
$imagick = new Imagick(
'https://media.geeksforgeeks.org/wp-content/uploads/geeksforgeeks-13.png');
// Create another Imagick object containing watermark
$watermark = new Imagick('label:This is my secret.');
// Hide $watermark inside $imagick
$imagick = $imagick->steganoImage($watermark, 64);
// Write image to the local folder
$imagick->writeImage('output.png');
// Set the offset
$imagick->setSizeOffset($watermark->getImageWidth(),
$watermark->getImageHeight(), 64);
// Read the encoded image and extract secret
$imagick->readImage('STEGANO:output.png');
// Show the output
$imagick->setImageFormat('png');
header("Content-Type: image/png");
echo $imagick->getImageBlob();
?>

Looks like new Imagick('LABEL:Hello World!'); is no longer enough for a simple label. You'll need to set the size of the canvas, and the point size BEFORE reading the label.
define('STEGANO_OFFSET', 64); // Secret offset
define('STEGANO_WIDTH', 88);
define('STEGANO_HEIGHT', 14);
$watermark = new Imagick();
$watermark->setSize(STEGANO_WIDTH, STEGANO_HEIGHT);
$watermark->setPointSize(16);
$watermark->readImage('LABEL:Hello World!');
$stegano = $image->steganoImage($watermark, STEGANO_OFFSET);
I can't speak when/why this changed, but if you run the following...
convert 'label:Hello World!' decoded.png
... you would have the same image previously extracted from STEGANO:

Related

How can I generate two colour product images dynamically?

I'm currently building an ecommerce site (with Drupal Commerce). We sell sports clothing that is made to order. The customer is able to pick a style, two colours and a size. For each style there are over three hundred combinations of colours that could be chosen.
I am creating artwork for the products in Illustrator. They are fairly simple vectors that use only two flat colours with a black outline on top.
I'm trying to find a way to generate all of the colour combinations for each style, preferably dynamically. I've looked at GD but I'm not sure that will work here. I wondered if there was a way of either using SVG (as I already have vectors) or stacking 3 transparent PNGs that could have a colour overlay applied and preserve their transparency? Done.
To create the images dynamically I have created one GIF that contains the white background and a pure red and pure blue region to define the primary and secondary areas. This is run through GD which changes the red and blue to the user selected colours. Then a transparent PNG is merged on top which contains the black outline and the company logo.
On index.php I have a form that allows users to choose a style and two colours:
<form method="post" action="index.php">
<label for="style">Style:</label>
<select id="style" name="style" required>
<option value="0001">Vertical Stripe</option>
<option value="0002">V Neck</option>
<option value="0003">Contrast Side</option>
...
</select>
<br><br>
<label for="color1">Color 1:</label>
<select id="color1" name="color1" required>
<option></option>
<option value="134,84,66">Retro Brown</option>
<option value="115,51,68">Claret</option>
<option value="167,57,52">Deep Red</option>
<option value="213,69,54">Bright Red</option>
...
</select>
...
</form>
After the form has been submitted there's some PHP to create a URL that passes the options over to product-image.php:
<?php
$url = "product-image.php";
if (isset($_POST["style"])) {
$url = $url . "?style=" . $_POST["style"];
}
if (isset($_POST["color1"])) {
$url = $url . "&color1=" . $_POST["color1"];
}
if (isset($_POST["color2"])) {
$url = $url . "&color2=" . $_POST["color2"];
}
?>
<img class="product" src="<?php echo $url; ?>">
Then the bulk of the work is done by product-image.php:
// Set some dummy values to avoid errors
$style = "0001";
$color1 = array(255,255,0);
$color2 = array(0,0,200);
if (isset($_GET["style"])) {
$style = $_GET["style"];
}
$colorFile = $style . "colors.gif";
$outlineFile = $style . "outline.png";
// Load image with coloured sections
$image_1 = imagecreatefromgif($colorFile);
// Load image with outlines
$image_2 = imagecreatefrompng($outlineFile);
imagealphablending($image_1, true);
imagesavealpha($image_1, true);
imagetruecolortopalette($image_1, false, 255);
// Import $color1 values to create an RGB array
if (isset($_GET["color1"])) {
$color1 = explode(',', $_GET["color1"]);
}
// Import $color2 values to create an RGB array
if (isset($_GET["color2"])) {
$color2 = explode(',', $_GET["color2"]);
}
// Define Primary (red) region
$region1 = imagecolorclosest ( $image_1, 255,0,0);
// Set new colour for $region1 using the values passed into $color1
imagecolorset($image_1, $region1, $color1[0], $color1[1], $color1[2]);
// Get Secondary (blue) region
$region2 = imagecolorclosest ( $image_1, 0,0,255);
// Set new colour for $region2 using the values passed into $color2
imagecolorset($image_1, $region2, $color2[0], $color2[1], $color2[2]);
// Create a true color canvas, this seems to retain transparency when merging PNG & GIF
$merged_image = imagecreatetruecolor(339, 390);
// Merge the newly coloured sections
imagecopy($merged_image, $image_1, 0, 0, 0, 0, 339, 390);
// Merge the outlines on top
imagecopy($merged_image, $image_2, 0, 0, 0, 0, 339, 390);
// Tell browser to expect PNG
header("Content-type: image/png");
// Output new PNG
imagepng($merged_image);
// Tidy up
imagedestroy($image_1);
imagedestroy($image_2);
imagedestroy($merged_image);
I am pretty chuffed with the results as I am still learning PHP and had never looked into GD before. I have posted a rough demo here (there is also a link to download all the files used on that page).
Any suggestions for improvements? Ultimately I want the user to select two colours in the drop downs and then a script will look to see if an image with those options exists and if not it dynamically creates it by setting the colour of the two regions and then stores the newly created image for future users.
How can I make it auto update without the need for a submit button?
All of the above works and now I've got it to store the images it creates and added a check to see if the image is there before it tries to create it too. The linked example has been updated with all the code but here's the new product-image.php file for anyone that's interested.
$style = "0001"; // Dummy values to avoid errors
$color1 = array(247,228,064);
$color2 = array(031,076,146);
$templatePath = "../templates/"; // Relative path from this file to your templates
if (isset($_GET["style"])) {
$style = $_GET["style"]; // Replace $style with real value if recieved
}
if (isset($_GET["color1"])) {
$color1 = explode(',', $_GET["color1"]); // Replace $color1 with real RGB array if recieved
}
if (isset($_GET["color2"])) {
$color2 = explode(',', $_GET["color2"]); // Replace $color2 with real RGB array if recieved
}
// Create unique output file name by concatenating all numerical values eg:0001247228522562146.png
$outputFileName = $style . implode("", $color1) . implode("", $color2) . ".png";
// Check if the image we want already exists
if (file_exists($outputFileName)) {
// If it does then open the file in a binary mode
$fp = fopen($outputFileName, 'rb');
// send the right headers
header("Content-Type: image/png");
header("Content-Length: " . filesize($outputFileName));
// dump the picture and stop the script
fpassthru($fp);
exit;
} else { // If it doesn't already exist then lets create the image...
$colorFile = $templatePath . $style . "colors.gif";
$outlineFile = $templatePath . $style . "outline.png";
$image_1 = imagecreatefromgif($colorFile); // Load image with coloured sections
$image_2 = imagecreatefrompng($outlineFile); // Load image with outlines
imagealphablending($image_1, true);
imagesavealpha($image_1, true);
imagetruecolortopalette($image_1, false, 255);
$region1 = imagecolorclosest ( $image_1, 255,0,0); // Get Primary (red) region
imagecolorset($image_1, $region1, $color1[0], $color1[1], $color1[2]); // Set new colour for $region1
$region2 = imagecolorclosest ( $image_1, 0,0,255); // Get Secondary (blue) region
imagecolorset($image_1, $region2, $color2[0], $color2[1], $color2[2]); // Set new colour for $region2
$merged_image = imagecreatetruecolor(339, 390); // Create a true color canvas
imagecopy($merged_image, $image_1, 0, 0, 0, 0, 339, 390); // Merge the newly coloured sections
imagecopy($merged_image, $image_2, 0, 0, 0, 0, 339, 390); // Merge the outlines on top
header("Content-type: image/png"); // Tell browser to expect PNG
imagepng($merged_image, $outputFileName); // Save new PNG to server
imagedestroy($image_1); // Tidy up
imagedestroy($image_2);
imagedestroy($merged_image);
// open the image we just created in a binary mode
$fp = fopen($outputFileName, 'rb');
// send the right headers
header("Content-Type: image/png");
header("Content-Length: " . filesize($outputFileName));
// dump the picture and stop the script
fpassthru($fp);
exit;
}
Using the code above and adding a few lines of jQuery I have finally achieved my original goal.
The jQuery:
$('select').click(function() {
var style = $("select#style").val();
var color1 = $("select#color1").val();
var color2 = $("select#color2").val();
var productImgURL = 'product-image.php?style='+ style + '&color1=' + color1 + '&color2=' + color2;
$('.product').attr('src',productImgURL);
});
As soon as the select box is modified the jQuery requests a different image from product-image.php by appending the values. The interaction is smooth and works exactly how I wanted.
Now I just have to figure out how to store the generated images and add a check to see if they have already been generated. Then I have to make all of this play nice with Drupal Commerce.
I have updated my example page and the all of the code is available for download there.
Although this question received no responses I wouldn't have figured this out without trawling through many other questions on this site so thanks to everyone who posts here!

Jscript image tag creation gives an error

function pushImage () {
var img = new Image();
img.src = '/waroot/chart/chart.png';
document.getElementById("test1").innerHTML = "<img src='/waroot/chart/chart.png'>";
document.getElementById("test2").innerHTML = img;
}
Test 1 works and shows the image, but test 2 doesn't. I am not sure how to solve it but i will need the way test 2 works further along my project since i'm going to have to circle through a large amount of images.
The images are created by JFreeCharts, saved to png and then have to be posted to a site. As a side question: is it possible to push the freecharts objects straight to the jscript instead of having to save them prior (i could throw them into the dictionary and then look them up later but i'm not sure if this works)
Use .appendChild(img) instead of .innerHTML:
function pushImage () {
var img = new Image();
img.src = '/waroot/chart/chart.png';
document.getElementById("test1").innerHTML = "<img src='/waroot/chart/chart.png'>";
document.getElementById("test2").appendChild(img);
}
Demo
This is because img is an image object, not an html string, so you have to append it to the DOM.
P.S., don't forget that the alt attribute is required in the img tag!

Load image and change width and height as3

i want to load image from remote url and synchronicity and change it width and height.
i am using the folowwing code, but it want let me change the width and highet, i think i needto convert the loader to a Bitmap object.
how can i do that, thank you very much.
var imageURLRequest:URLRequest = new URLRequest(pic);
var myImageLoader:Loader = new Loader();
myImageLoader.load(imageURLRequest);
var urlRequest:URLRequest = new URLRequest(pic);
var loader:Loader = new Loader();
loader.load(urlRequest);
trace(loader.width); // return 0
loader.width =100; //dosent work
allMC[i].img.addChild(loader);
To access what the loader loaded, use loader.content reference. If you are loading an image, you can retrieve its raw data via (loader.content as Bitmap).bitmapData, of course first check if it's so via if (loader.content is Bitmap). Also, you need to do all of this after your loader will finish loading, it'll send an event indicating this.
...
loader.load(urlRequest);
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, loaderComplete);
...
private function loaderComplete(e:Event):void {
// now your image is fully loaded
trace(loader.content.width);
// etc etc, whatever you need to do with your image prior to
// addressing it from elsewhere.
}

Getting an image from an XMLHttpRequest and displaying it

I got this web service that gives me a (jpeg) image. What I want is take this image, convert it into a Data URI and display it on an HTML5 canvas, like that:
obj = {};
obj.xmlDoc = new window.XMLHttpRequest();
obj.xmlDoc.open("GET", "/cgi-bin/mjpegcgi.cgi?x=1",false, "admin", "admin");
obj.xmlDoc.send("");
obj.oCanvas = document.getElementById("canvas-processor");
obj.canvasProcessorContext = obj.oCanvas.getContext("2d");
obj.base64Img = window.btoa(unescape(encodeURIComponent( obj.xmlDoc.responseText )));
obj.img = new Image();
obj.src = 'data:image/jpeg;base64,' + obj.base64Img;
obj.img.src = obj.src
obj.canvasProcessorContext.drawImage(obj.img,0,0);
Unfortunately, this piece of code doesn't work; the image is not painted on the canvas at all (plus it seems to have width and height = 0, could it be not decoded correctly? I get no exceptions). img.src looks like data:image/jpeg;base64,77+977+977+977+9ABBKRklG....
Resolved: turns out I should have overridden the mime type with:
req.overrideMimeType('text/plain; charset=x-user-defined');
and set the response type with:
req.responseType = 'arraybuffer';
(see this. You should make an asynchronous request if you change the response type, too).
First you need to create an img element (which is hidden)
Then you do exactly what you have done except that you listen to your onload event on your img element.
When this event is launched you are able to get the width and height of your pictures so you can set your canvas to the same size.
The you can draw your image as you did in last line.

Magento crop image?

I found this: http://docs.magentocommerce.com/Varien/Varien_Image/Varien_Image.html#crop
But I'm not sure if this is deprecated or something because when I tried this:
echo rawurlencode($this->helper('catalog/image')->init($_product, 'image')->constrainOnly(TRUE)->keepAspectRatio(TRUE)->keepFrame(FALSE)->setWatermarkImageOpacity(0)->crop(10, 20, 30, 40)->resize(300, null))
It doesn't work and gives me this error:
Fatal error: Call to undefined method Mage_Catalog_Helper_Image::crop() in /home/xxxxx/public_html/app/design/frontend/default/xxxxx/template/catalog/product/view.phtml
So is the crop() method actually usable at all? If it is, how can I use it to crop (not to be confused with resize) the product images of Magento? Thanks!
Your mistake is assuming that $this->helper('catalog/image')->init($_product, 'image') returns a Varien_Image instance, when in fact there are two intermediate classes involved:
Mage_Catalog_Helper_Image and Mage_Catalog_Model_Product_Image.
The catalog/image helper is a mess, even though it has been cleaned up a bit in recent versions (e.g. no more private methods). Still, some getters still are protected without there being a real need for it.
Here is my workaround:
/* #var $imageHelper Mage_Catalog_Helper_Image */
// Initialize the image helper
$imageHelper = Mage::helper('catalog/image')->init($_product, 'image')
->constrainOnly(true)
->keepAspectRatio(true)
->keepFrame(false)
->setWatermarkImageOpacity(0);
// Get the catalog/product_image instance
/* #var $imageModel Mage_Catalog_Model_Product_Image */
$reflection = new ReflectionClass($imageHelper);
$property = $reflection->getProperty('_model');
$property->setAccessible(true);
$imageModel = $property->getValue($imageHelper);
// Initialize the missing values on the image model
// Usually done in Mage_Catalog_Helper_Image::__toString()
if (! $imageModel->isCached())
{
$getWatermarkMethod = $reflection->getMethod('getWatermark');
$getWatermarkMethod->setAccessible(true);
$imageModel->setBaseFile($_product->getImage())
->resize()
->setWatermark($getWatermarkMethod->invoke($imageHelper));
// Crop the image using the image processor
// $imageModel->getImageProcessor() returns a Varien_Image instance
$imageModel->getImageProcessor()->crop(10, 20, 30, 40);
// Generate the image according to the set parameters and
// get the URL while bypassing the helper to avoid reinitialization
$url = $imageModel->saveFile()->getUrl();
}
echo $url . "\n";
It would be easier to use the catalog/product_image model or Varien_Image directly, but this way all the Magento watermark settings still are applied.
Either way isn't clean.
I hope the getters on the helper are made public in future releases.
Here is the alternative method ( credits from Onlinebizsoft.com )
The following code first looking the image that available in the /resize directory, if it's not there, doing rest of things.
// actual path of image
$_imageUrl = Mage::getBaseDir('media').DS."myimage".DS.$post->getThumbnail();
// path of the resized image to be saved
// here, the resized image is saved in media/resized folder
$imageResized = Mage::getBaseDir('media').DS."myimage".DS."resized".DS.$post->getThumbnail();
// resize image only if the image file exists and the resized image file doesn't exist
// the image is resized proportionally with the width/height 135px
if (!file_exists($imageResized)&&file_exists($_imageUrl)) :
$imageObj = new Varien_Image($_imageUrl);
$imageObj->constrainOnly(TRUE);
$imageObj->keepAspectRatio(TRUE);
$imageObj->keepFrame(FALSE);
$imageObj->resize(135, 135);
$imageObj->save($imageResized);
endif;
Check the website Resize - Scale Crop images
Did you tried Varien_Image class ?
$image = new Varien_Image($img);
$cropped = $image->crop();

Resources