phpImageWorkshop: Removing a layer after saving - php

In the phpImageWorkshop documentation (http://phpimageworkshop.com/doc/13/saving.html) it says:
...after saving, you'll be able to continue to use your document and
to perform some actions on its sublayers, really convenient !
However, after calling save() I'm unable to remove the watermark layer.
I start by loading the photo and watermark and resize the photo:
$photo = PHPImageWorkshop\ImageWorkshop::initFromPath($tmp_name);
$mark = PHPImageWorkshop\ImageWorkshop::initFromPath($watermark);
$photo->resizeInPixel(960, null, true);
And then I add the watermark, save the photo, then remove the watermark (so I can make other sizes without a watermark without creating a new object):
$photo->addLayer(1, $mark, 0, 0, 'LB');
$photo->save($path, $filename, false, null, 80); // file correctly has watermark
$photo->remove(1);
$photo->resizeInPixel(550, null, true);
$photo->save($path, $filename, false, null, 80); // file has watermark, not correct
This does not delete the watermark layer. However, if I call remove() before save() it will remove the watermark:
$photo->addLayer(1, $mark, 0, 0, 'LB');
$photo->remove(1); // calling remove() before save removes watermark
$photo->save($path, $filename, false, null, 80); // file does not have watermark
I cannot understand why this is happening, since the documentation clearly says calling save() does not change the layers.
I've confirmed that the watermark layer is being put on layer level 1, and it works OK if I do not call save().

Despite the documentation saying you'll be able to continue to use your document, the fact is that the save() function calls getResult() which returns a merged resource image (this is in ImageWorkshopLayer.php)
However, if you create a 'base layer' and add the photo and watermark on top of it, the save() function appears to merge to the base layer - leaving the photo and mark untouched, so you can remove the mark and re-save (which causes the photo to be re-merged onto the base layer) i.e.
$baseimg = PHPImageWorkshop\ImageWorkshop::initVirginLayer(1024,800);
$photo = PHPImageWorkshop\ImageWorkshop::initFromPath("test.png");
$mark = PHPImageWorkshop\ImageWorkshop::initFromPath("test2.png");
$iphoto= $baseimg->addLayerOnTop($photo, 0, 0, 'LB');
$imark= $baseimg->addLayerOnTop($mark, 0, 0, 'LB');
$baseimg->resizeInPixel(960, null, true);
// file correctly has watermark
$baseimg->save(__DIR__, "test_out.png", false, null, 80);
$baseimg->remove($imark['id']);
// file correctly has no watermark
$baseimg->save(__DIR__, "test_out2.png", false, null, 80);
Note that I use the return value from addLayerOnTop() to determine the 'id' pf the layer to remove.
EDIT: although the above works, it is not ideal because you really need the resulting image to be the size of the re-sized photo. Also I found that once the photo is made a layer, you have to resize that layer (not the original photo) so...
// load photo and mark
$photo = PHPImageWorkshop\ImageWorkshop::initFromPath("test.png");
$mark = PHPImageWorkshop\ImageWorkshop::initFromPath("test2.png");
// resize the photo 1st time
$photo->resizeInPixel(960,null, true);
$width= $photo->getWidth();
$height= $photo->getHeight();
// make empty base image same size as photo
$baseimg = PHPImageWorkshop\ImageWorkshop::initVirginLayer($width,$height);
// add photo and mark onto base image
$iphoto= $baseimg->addLayerOnTop($photo, 0, 0, 'LT');
$imark= $baseimg->addLayerOnTop($mark, 0, 0, 'LT');
$photoid= $iphoto['id']; // get layer id's
$markid= $imark['id'];
// file correctly has watermark
$baseimg->save(__DIR__, "test_out.png", false, null, 80);
// remove mark layer
$baseimg->remove($imark['id']);
// resize photo again
// - photo is now a layer in baseimg
$baseimg->layers[$photoid]->resizeInPixel(550,null, true);
$width= $baseimg->layers[$photoid]->getWidth();
$height= $baseimg->layers[$photoid]->getHeight();
// crop baseimg to match photo size
$baseimg->cropInPixel($width,$height);
// file correctly has no watermark
$baseimg->save(__DIR__, "test_out2.png", false, null, 80);
That seems to work fine now.

Related

spatie medialibrary defining fallback image for each convertion

with spatie/medialibrary package i have 3 conversions in registerMediaConversions method like this
public function registerMediaConversions(Media $media = null): void
{
$this->addMediaConversion('thumb')
->fit(MANIPULATIONS::FIT_STRETCH, 140, 260);
$this->addMediaConversion('slider')
->fit(MANIPULATIONS::FIT_STRETCH, 275, 720);
$this->addMediaConversion('mini')
->fit(MANIPULATIONS::FIT_STRETCH, 55, 85);
}
the thing i want is that i can define a useFallbackUrl image for each of these conversions. i know i can define fallback image on registerMediaCollections method, but this will apply on every conversion, instead i want to define a different fallback image for each one of them.
how can i do that?

Laravel Image Intervention avoid rotation

I'm uploading an iPhone image - taken by iPhone camera in vertical - with the dimensions of 2448x3264 and because this dimensions are so high (?) when I create a thumb of 600x360 it automatically rotates to horizontal.
What have I tried without any success:
Change the thumb dimensions
Use the fit function
Use the resize function
Use the crop function
Use the upsize and aspectRatio methods
Set only the height and use null on width
Set only the width and use null on height
The thumb must have a maximum of height of 360 and I'm ok if the width is not 600.
$imageResize = Image::make($originalFile);
$imageResize->fit(600, 360, function ($constraint)
{
$constraint->upsize();
});
$imageResize->save($thumbPath);
My goal is to have:
Thumbnails in vertical if the original photo is vertical
Thumbnails in horizontal if the original photo is horizontal
How can I achieve this?
As spoke before, the image is being saved in its correct orientation and at the point of resizing you are running the fit() function on which I was able to find some information on this issue running along side that which suggests you need to use orientate() with fit.
An example here:
$imageResize = Image::make($originalFile);
$imageResize->orientate()
->fit(600, 360, function ($constraint) {
$constraint->upsize();
})
->save($thumbPath);
I'm glad this helped.
According to this github issue you may need to run orientate() before fit():
$imageResize = Image::make($originalFile)
->orientate()
->fit(600, 360, function ($constraint) {
$constraint->upsize();
})
->save($thumbPath);
$img = Image::make($originalFile);
$img->orientate();
$img->resize(1024, null, function($constraint){
$constraint->upsize();
$constraint->aspectRatio();
});
$img->save();

How can reduce height and download pdf using FPDF?

I have a function to generate pdf using Fpdf in laravel.
My problems are:
After all Cell I have some extra space. I need to remove that. Please find the image given below.
How can I download this pdf file in to my system. Currently it's just showing in to browser. Code samples are given below.
Code
Controller: Controller.php
public function index()
{
$orders = Order::select('firstname', 'lastname', 'street', 'postal', 'country')->get();
foreach ($orders as $order){
Fpdf::SetMargins(5, 5, 5);
Fpdf::AddPage('L', array(60,90), 'A4');
Fpdf::SetAutoPageBreak(TRUE, 0);
Fpdf::SetFont('helvetica', '', 7); //IF bold letter SetFont('Arial','B',14)
Fpdf::SetTextColor(0, 0, 0);
Fpdf::Cell(10,5,iconv('UTF-8', 'windows-1252', 'Falls unzustellbar, zurück an Absender'),0,"1","L");
Fpdf::SetFont('','U');
Fpdf::Cell(10,5,iconv('UTF-8', 'windows-1252', 'schrillALARM.jetzt c/o 365group • Grasgasse 2 • 93047 Regensburg'),0,"1","L");
Fpdf::SetFont('helvetica', '', 11);
Fpdf::Cell(10,5,$order->firstname,0,1,"L");
Fpdf::Cell(10,5,$order->lastname,0,1,"L");
Fpdf::Cell(10,5,$order->street,0,1,"L");
Fpdf::Cell(10,5,$order->postal,0,1,"L");
Fpdf::Cell(10,5,$order->country,0,1,"L");
}
Fpdf::Output();
exit;
}
Route: Route::get('/test', 'Controller#index');
No experience with FDPF, but you can download this way:
Route::get(
'download/pdf/{pdf}',
function ($pdf) {
$file = // Get file
return response()->download($file);
}
);
Or just from your controller with
return response()->download($pdf);
for saving, just specify output path and filename in your output call string
Fpdf::Output([string dest [, string name [, boolean isUTF8]]])
For your white space though, when you're constructing your PDF document, you can use a default size of one of the following: A3, A4, A5, Letter, Legal with A4 being default. However, you can also declare custom sizes. This is more than likely what you're looking for, as you'll want to play with the sizes to get it with the amount of white space you're looking for. FPDF puts out the canvas first then fills it, so you're white space is coming from a canvas that is too big. This can be done in the constructor, or AddPage as you have done.
VIA Constructor:
//(L)andscape or (P)ortrait, unit type (mm millimeters), array size in mm
$pdf = new FPDF('L','mm',array(100,150));
VIA AddPage (must likely what you're looking for):
currently you have:
Fpdf::AddPage('L', array(60,90), 'A4');
however, params are supposed to be landscape/portrait, Predefined or custom size array, then rotation. So try this:
Fpdf::AddPage('L', array(60,90));
Now you'll need to play with those numbers, more than likely the 90, and shorten that up to rid yourself of the white space.

How to rotate full page with tcpdf?

I am using TCPDF library to write a custom size label with background image and multiple text blocks on it.
The user when sees the preview on screen of the PDF it should show in horizontal, but for printing, I need the full page rotated -90 degrees.
How can I just rotate the whole page for printing version without having to move anything?
Basically:
In my case I've already had to use a new document format for the special sizes my document required.
So I've duplicated that format, created one for Landscape and one for Portrait.
Then based on the $preview variable, if previewing I'm rendering the normal landscape document, but if not previewing, I'm using the Portrait format and orientation and also starting the transformation and rotating everything on page.
Hope this helps someone I've found no other "quick" way to accomplish this kind of full-page rotation.
<?php
// #1 get the preview attribute from
// the form that was submitted from the user
$preview= isset($_POST['preview'])?(int)$_POST['preview']:0;
// load TCPDF for CodeIgniter as a library
$this->load->library('Pdf');
// #2 set default orientation and format
$orientation='L';
$format='MAKE-L';
// #3 if not previewing, switch orientation and format to portrait
if (!$preview) {
$orientation='P';
$format='MAKE-P';
}
// create new pdf object
// (same as doing new TCPDF(), it is just the CodeIgniter wrapper)
$pdf = new Pdf($orientation, 'mm', $format, true, 'UTF-8', false);
// remove default header/footer
$pdf->setPrintHeader(false);
$pdf->setPrintFooter(false);
$pdf->SetMargins(0, 0, 0);
$pdf->AddPage($orientation, $format);
// #4 if not previewing, start transformation
// and rotate everything before inserting any content
if (!$preview) {
// Start Transformation
$pdf->StartTransform();
// Rotate counter-clockwise centered by (x,y)
$pdf->Rotate(-90, 70, 70); // <-- TODO: test this very well because 70 and 70 was just guessing, there is no math behind that so not sure if it will work always
}
// put your content here,
// for example set font and add a text
$pdf->SetFont('times', '', 7, '', true);
$pdf->writeHTMLCell(0, 0, 25.4, 2, 'lot number', 0, 1, 0, true, '', true);
/// end content
// #5 if not in preview mode, finish the transformation
if (!$preview) {
// Stop Transformation
$pdf->StopTransform();
}
$pdf->Output('example.pdf', 'I');
/**
* Last but very important note:
* I have added my formats in tcpdf/includes/tcpdf_static.php file.
* >> MAKE-L for Landscape
* >> MAKE-P for Portrait
*/
public static $page_formats = array(
// Make
'MAKE-L' => array( 396.850, 425.196), // = ( h 140 x w 150 ) mm
// Make
'MAKE-P' => array( 425.196, 396.850 ), // = ( h 140 x w 150 ) mm
// .. rest of formats here ../
);
The setPageFormat() method should do the job. You also can pass the parameter to the $format parameter of AddPage():
$pdf->AddPage($orientation, ['format' => $format, 'Rotate' => -90]);

tcpdf imagebox and cropping

I would like to add a 'imagebox' a box which contains the image and crops exceeding image value that is outside of this box. something like this:
I am not sure on how to do this if it's even possible.
Actually you can do this with Clipping.
The below line would show a photo of 200X300:
$pdf->Image('photo.JPG', 100, 100, 200, 300, '', true, '', false, 300);
To clip it you need:
$pdf->StartTransform();
$pdf->Rect(100, 100, 200, 300, 'CNZ'); //Clipping mask (CNZ style makes your day)
$pdf->Image('photo.JPG', 50, 50, 300, 400, '', true, '', false, 300);
//this would actually cut off a 50 units a in each direction.
$pdf->StopTransform();
You could crop an image with php , store it as a temp_file pass it to tcpfd and then delete it after the rendering of the pdf was done . Another option would be to use html/css to position a html element over the image but as we all know tcpdf doesn't know too much about css so i don't know if it will work .

Categories