Magento crop image? - 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();

Related

Imagick::steganoImage() Unable to show the watermark

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:

Importing products into Magento breaks images on existing products

After exporting, changing some details and then importing a large number of products into Magento, I noticed all the images are no longer set. The images still exist in the media gallery for each product, but they are not set as the base image.
I've seen that in some cases, you need to copy images over to a /media/import/ folder, but is it possible to change the import file so that I can keep the images where they are?
Right now, all the images appear to be in a folder: /media/catalog/product/
Any help would be very appreciated.
Additionally, if it were possible to run a script that sets all product's base image to the first image in its gallery, that would work just as well. Thanks!
Let's say that you have load the products and you are ready to make a change and save them. With this code:
if (file_exists($imagePath)) {//New image file
//Load your media table
$mediaApi = Mage::getModel("catalog/product_attribute_media_api");
try {
//Now you have all the images available for your product
//if you previously have assign anything
$items = $mediaApi->items($product->getId());
//loop them
foreach ($items as $item) {
//With that line you can remove them if you want
echo ($mediaApi->remove($product->getId(), $item['file']));
}
} catch (Exception $exception) {
var_dump($exception);
die('Exception Thrown');
}
$cache = Mage::getSingleton('core/cache');
$cache->flush();
//You need that line
$product->setMediaGallery(array('images' => array(), 'values' => array()));
//That line assigns your new image.As base,thumbail and image.
//Use it in the loop if you want to reassign an existing image.
$product->addImageToMediaGallery($imagePath, array('thumbnail', 'small_image', 'image'), false, false);
I hope that helps you
Cheers!

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!

Change the content type to image/png - cakephp

I have a cakephp application .I understand that my app uses a default.ctp for its layout .In default layout my header is set to html/text .I want to change my header type to image/png .Where should i change it ? Pls someone help me
Code:
$this->layout=NULL;
$this->autoRender=false;
$this->RequestHandler->respondAs('image/jpg');
View Coding :(index.ctp)
<?php
session_start();
$text = rand(10000,99999);
$_SESSION["vercode"] = $text;
$height = 25;
$width = 65;
$image_p = imagecreate($width, $height);
$black = imagecolorallocate($image_p, 0, 0, 0);
$white = imagecolorallocate($image_p, 255, 255, 255);
$font_size = 14;
imagestring($image_p, $font_size, 5, 5, $text, $white);
imagejpeg($image_p, null, 80);
?>
Controller coding :
public function index()
{
$this->layout=false;
$this->response->type('png');
}
Note: CakePHP version 2.3.0
Using CakePHP 3
You should always try to do it the CakePHP way instead of setting the headers manually by using PHP's header() function. In this case, the documentation was not very clear. I had to figure it out.
This is how I made it work using CakePHP 3.3:
First, get the contents of the image into a variable, because we want CakePHP to render that content, not just output and die.
Then destroy the image resource to free memory.
Optional: you may set cache headers. (commented in the code below)
Set response object type to "jpg" or "png", etc. See docs
Set the layout to: "false"
Output the image to the response body and set autoRender to false to avoid creating an unnecessary template file (.ctp).
// Controller method
public function image($id = null) {
// Create an image resource: $image ...
ob_start();
imagejpeg($image);
$buffer = ob_get_clean();
imagedestroy($image);
// $this->response->cache('-1 minute', '+1 days');
$this->response->type('jpg');
$this->viewBuilder()->layout(false);
$this->response->body($buffer);
$this->autoRender = false;
}
If you really must return the content of your view/layout as image (which I highly doubt):
$this->response->type('png'); // as documented in the 2.x docs
will automatically set image/png as response type for the header.
If you need to render your view without layout try
$this->layout = false;
// OR
$this->render('my_view', false); // false should not render a layout
You cannot use "null" as it renders the default layout.
Either way, never call header() stuff in your view, always in your controller via response object.
(Yeah, old thread, but I just came across this problem.)
$this->autoRender = false;
header('Content-Type: image/png');
in a Controller's method worked for me.

Resizing magento gallery images

i am trying to display product gallery images in my custom cms home page. If i use the code from media.phtml to display the gallery images, it does not work. I found this piece of code and it worked.
<div id="thumbs" class = "thumbs-home">
<?php
$obj = new Mage_Catalog_Block_Product_View_Media();
$_product1 = new Mage_Catalog_Model_Product();
// Load all product information of a particular product
$Products_one = Mage::getModel('catalog/product')->load($productId);
// Use your Product Id instead of $id
$countt = count($Products_one->getMediaGalleryImages());
if($countt>0){
foreach ($Products_one->getMediaGalleryImages() as $_image)
{
// For the Original Image
$thumb_img = "<img src=".Mage::getBaseUrl(Mage_Core_Model_Store::URL_TYPE_MEDIA).str_replace(Mage::getBaseUrl('media'),"",$_image->url)." alt=''width='60' height='60' />";
echo "<a href='".Mage::getBaseUrl(Mage_Core_Model_Store::URL_TYPE_MEDIA).str_replace(Mage::getBaseUrl('media'),"",$_image->url)."'rel='lightbox[gallery]'>".$thumb_img."</a>";
//For gallery Image
//$resizeimage = $obj->helper('catalog/image')->init($_product, 'thumbnail', $_image->getFile())->backgroundColor(242,242,243)->resize(400,300);
//echo "<img src=".$resizeimage."alt='' />";
}
}
?>
This gets the actual images and gets resized by the width and height attributes. But i want to resize the image through magento. The last piece of code $resizeimage is not working for some reason. How can i make this work? The problem is that i am using a lightbox to display the gallery images which displays the actual high resolution images that are too large. The light box takes in width and height of image provided and i am not able to figure out as to how i set a standard dimensions for the light box. So the only other option is the have the images resized by magento before passing them to the lightbox. Thanks.
You just need to call proper object, instead of $obj->helper you should use Mage::helper, so your call should look like this:
print Mage::helper('catalog/image')
->init($product, 'thumbnail', $image->getFile())
->backgroundColor(255,255,255)
->resize(100,100);
And that's it! :)

Resources