Related
Right now I'm working on a Symfony web app, and it is using TCPDF to print receipts. I would like to know if there is a way/method to know how long is part of my content and compare it to the rest of the empty page. If the content is larger than the rest of the page, it would give a add another page and put the content there.
For example, I have 3 tables in my first page. If the first two tables occupy 80% of the page, and the third will ocupy 50%, compare those 50% to the 20% remaining of the first page, and since the content is bigger than the rest of the page, add another page and put table 3 there.
I don't have any code to show right now, but I am asking now since this is something I will have to do in the future (and I know there have been alot of problems with overlapping tables)
There's a function I use called public function checkHeights() that, as the name suggests, checks the heights of an element in TCPDF.
public function checkHeights($pdf, $array, $checkHeight = 10){
$max_height = 0;
foreach($array AS $item){
$current_height = $pdf->getStringHeight($item["width"], $item["text"], false, true, '', 1);
if($current_height >= $max_height){
$max_height = $current_height;
}
}
$page_height = $pdf->getPageHeight();
$margins = $pdf->getMargins();
if($pdf->GetY() + $max_height >= ($page_height - $margins["bottom"] - $checkHeight)){
$size = $pdf->getFontSizePt();
$style = $pdf->getFontStyle();
$pdf->SetFont('helvetica', 'I', 6.5, '', true);
$pdf->SetColor("text", 155, 155, 155);
$pdf->Cell(0, 0, 'Continued...', 'T', 0, 'R', 0, '', 0, false, 'T', 'T');
$pdf->SetFont('helvetica', $style, $size, '', true);
$pdf->SetColor("text", 0, 0, 0);
$pdf->addPage();
$pdf->Cell(0, 0, '', 'B', 1, 'R', 0, '', 0, false, 'T', 'T');
}
return $max_height;
}
It accepts 3 variables: Your $pdf object, an array of arrays containing cell information and the height (space from the bottom) to check against.
There are two ways to use this function. Firstly, checking to see if a single Cell will take up the remaining space on a given page:
self::checkHeights($pdf, array(array("width" => 0, "text" => "")));
If there isn't enough space, it will save your font and style settings and add a small Continued... to the right side of your page.
Secondly, passing in the contents of a row (or list of Multicell items):
$height = Self::checkHeights($pdf, array(array("width" => 45, "text" => "Example"), array("width" => 54, "text" => "Example"), array("width" => 52, "text" => "Example"), array("width" => 26, "text" => "Example"), array("width" => 0, "text" => "Example")));
In this example, the current row item has 5 cells, with widths of 45, 54, 52, 26 and 0 (0 being the remaining horizontal space). It also takes into account cell wrapping (ie making the row grow in height to accommodate text overflow) and will add the Continued... text if it's too long.
Once you have $height defined and a new page added (if necessary), you would create your row of Multicells:
$pdf->MultiCell(45, $height, "Example", 'L', 'L', 0, 0, '', '', true, 0, false, true, $height, 'M');
$pdf->MultiCell(54, $height, "Example", 0, 'R', 0, 0, '', '', true, 0, false, true, $height, 'M');
$pdf->MultiCell(52, $height, "Example", 0, 'R', 0, 0, '', '', true, 0, false, true, $height, 'M');
$pdf->MultiCell(26, $height, "Example", 0, 'C', 0, 0, '', '', true, 0, false, true, $height, 'M');
$pdf->MultiCell(0, $height, "Example", 'R', 'R', 0, 1, '', '', true, 0, false, true, $height, 'M');
Refer to the TCPDF documentation for using ->MultiCell() function, but the important ones are the ones that use $height and the last one, which is vertical alignment.
Essentially, checkHeights() is a way to construct cells in a row that all have the same height, based on the content, but also a way to check if a cell will use up the remaining vertical space on the page, and add a page before outputting a new cell. If you need more clarification, let me know.
$style = array('width' => 0.5, 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => array(255, 0, 0));
$pdf->Line(5, 10, 80, 30, $style);
I uses the above statements to draw a line.
Result view in screen has this line drawn.
However It's not printed on paper.
Any help would be highly appreciated.
I'm sorry folks, it's not TCPDF problem.
I was using Google to print out the PDF generated and having this problem.
If I try Internet Explorer there is no problem.
Background, I am converting images to ascii art. This works perfectly and even works with 24-bit color, converting the colors to the right rgb values. However, I now want to render the ascii art in 4-bit color palette rather than 24-bit.
How do I convert 24-bit colors to 4-bit with PHP?
More specifically, I have the standard IRC color pallet which I need to convert any given Hexidecimal or RGB value to. It is preferred that the colors match as best as possible when converted to the 4-bit color.
Other ideas I have had on this are to convert the image itself to a 4-bit palette (using GD, which is what I use to read in the colors right now) before trying to grab colors off of it. And another idea might be to define a color range for each of the following color and just check that the given 24-bit color is in the range, however I wouldn't know how to get the ranges for all colors into that palette.
imagetruecolortopalette allows you to reduce the colours, but results can vary wildly and I don't know if there is a way of 'mapping' the colours correctly or specifying the palette.
Test image (24-bit):
Reduced to 4-bit (without dithering):
$img = imagecreatefrompng('Bliss.png');
imagetruecolortopalette($img, false, 16);
imagepng($img, 'Bliss2.png');
Reduced to 4-bit (with dithering):
$img = imagecreatefrompng('Bliss.png');
imagetruecolortopalette($img, true, 16);
imagepng($img, 'Bliss3.png');
As you can see, results are far from perfect. But perhaps this is a good start for you.
In the end, despite the wonderful suggestions surrounding imagemagick I found a good solution using straight php. I was able to calculate the closest color through the use of delta E 2000 with a modified version of php-color-difference library found on github, here is my fork: https://github.com/nalipaz/php-color-difference
The pertinent example is:
<?php
include('lib/color_difference.class.php');
$palette = array(
'00' => array(255, 255, 255),
'01' => array(0, 0, 0),
'02' => array(0, 0, 139),
'03' => array(0, 128, 0),
'04' => array(255, 0, 0),
'05' => array(139, 0, 0),
'06' => array(128, 0, 128),
'07' => array(255, 165, 0),
'08' => array(255, 255, 0),
'09' => array(50, 205, 50),
'10' => array(0, 128, 128),
'11' => array(173, 216, 230),
'12' => array(0, 0, 255),
'13' => array(255, 105, 180),
'14' => array(128, 128, 128),
'15' => array(211, 211, 211),
);
$color_rgb = array(255, 255, 128);
$color_delta_e = new color_difference($color_rgb);
$match_index = $color_delta_e->getClosestMatch($palette);
$color = $palette[$match_index];
I am pretty happy with this solution and smaller amount of overhead. Thanks for the suggestions guys.
I think ImageMagick (or GraphicsMagick) can do this with the -depth option. There's a discussion of it here: http://www.imagemagick.org/discourse-server/viewtopic.php?f=1&t=15395
UPDATE: I should add that ImageMagick is not a PHP library, however there's a PECL wrapper (imagick) for it at http://pecl.php.net/package/imagick.
I think you need to use remap to map the colours in the image to the palette of colours in your swatch. I do it at the command line like this:
convert image.jpg -remap palette.jpg out.jpg
You may, or may not want the dither option - check it out.
Original image is here:
and this is my palette.jpg (you only need a really small image, this is way too big - I will address this shortly)
and the result
You can also create your palette according to the colours you want using ImageMagick. I hand-coded the following and didn't pay too much attention, so you would want to check the RGB values in here before assuming they are correct:
#/bin/bash
cat<<EOF | convert txt:- palette.png
# ImageMagick pixel enumeration: 8,2,256,rgb
0,0: (255,255,255)
1,0: (0,0,0)
2,0: (0,0,255)
3,0: (255,255,0)
4,0: (255,0,0)
5,0: (128,128,128)
6,0: (255,105,180)
7,0: (173,216,230)
0,1: (50,205,50)
1,1: (139,0,0)
2,1: (255,165,0)
3,1: (128,0,128)
4,1: (0,0,139)
5,1: (0,128,128)
6,1: (0,128,0)
7,1: (211,211,211)
EOF
Basically, the script above gives ImageMagick the RGB values as text and asks it to make small 8x2 image that looks like this:
Then you would use this palette with your remap operation.
I'm trying to sharpen resized images using this code:
imageconvolution($imageResource, array(
array( -1, -1, -1 ),
array( -1, 16, -1 ),
array( -1, -1, -1 ),
), 8, 0);
When the transparent PNG image is sharpened, using code above, it appears with a black dot in the upper left corner (I have tried different convolution kernels, but the result is the same). After resizing the image looked OK.
1st image is the original one
2nd image is the sharpened one
EDIT: What am I going wrong? I'm using the color retrieved from pixel.
$color = imagecolorat($imageResource, 0, 0);
imageconvolution($imageResource, array(
array( -1, -1, -1 ),
array( -1, 16, -1 ),
array( -1, -1, -1 ),
), 8, 0);
imagesetpixel($imageResource, 0, 0, $color);
Is imagecolorat the right function? Or is the position correct?
EDIT2: I have changed coordinates, but still no luck. I've check the transparency given by imagecolorat (according to this post). This is the dump:
array(4) {
red => 0
green => 0
blue => 0
alpha => 127
}
Alpha 127 = 100% transparent. Those zeroes might cause the problem...
Looks like a bug in the convolution code (corners are special cases in some implementations).
As a workaround, you can save the pixel value in that corner just before the convolution and restore it afterwards, with imageSetPixel().
The pixel you need to save is at (0,0), and possibly you will need to also check the transparency (but I think it should work with just imageColorAt and imageSetPixel).
TEST CODE
The file 'giants.png' I wgot from the one you posted above. If I do not use imageSetPixel I experience the same extra pixel you got. With imageSetPixel, the image looks correct to me.
Possibly there's some slight difference in the sequence I run ImageSaveAlpha or set alpha blending.
<?php
$giants = ImageCreateFromPNG('giants.png');
$imageResource = ImageCreateTrueColor(190, 190);
ImageColorTransparent($imageResource, ImageColorAllocateAlpha($imageResource, 0, 0, 0, 127));
ImageAlphaBlending($imageResource, False);
ImageSaveAlpha($imageResource, True);
ImageCopyResampled($imageResource, $giants, 0, 0, 0, 0, 190, 190, ImageSX($giants), ImageSY($giants));
$color = ImageColorAt($imageResource, 0, 0);
ImageConvolution($imageResource, array(
array( -1, -1, -1 ),
array( -1, 16, -1 ),
array( -1, -1, -1 ),
), 8, 0);
ImageSetPixel($imageResource, 0, 0, $color);
ImagePNG($imageResource, 'dwarves.png');
?>
I have created a custom header for my PDF created with TCPDF. Now I would like to add a blue line (about 2px width) that goes across the page at the bottom of the header but can't figure out how?
I believe you do it like this:
$style = array('width' => 0.5, 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => array(255, 0, 0));
$pdf->Line(5, 10, 80, 30, $style);
Here is the full example
http://www.tcpdf.org/examples/example_012.phps
I found the easiest way to put line
$pdf->writeHTML("<hr>", true, false, false, false, '');
You can also use the page axis:
$pdf->Line(5, $pdf->y, $pdf->w - 5, $pdf->y);
However if you are trying to render a colored <hr> html tag you will need to adjust the TCPDF::DrawColor (this excerpt is from code that adds a graph bar to each row of a data report as per $twidth and $lengthmm):
$htmlbar = '<hr style="width:' . $lengthmm . 'mm;">';
$oldDrawColor = $pdf->DrawColor;
$pdf->setDrawColor(121, 161, 46);
$pdf->MultiCell($twidth,'2',$htmlbar,0,'L',$fill,1,'','',true,0,true,false,4,'T',false);
$pdf->DrawColor = $oldDrawColor;
Drawing a horizontal black line at the current position:
$style = ['width' => 0.2, 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => [0, 0, 0]];
$this->pdf->SetLineStyle($style);
$this->pdf->Line(PDF_MARGIN_LEFT, $this->pdf->getY(), $this->pdf->getPageWidth()-PDF_MARGIN_LEFT, $this->pdf->getY());
$this->pdf->Ln();
The point is to get the x value for the second point.
This is how I do it:
$pageWidth = $pdf->getPageWidth(); // Get total page width, without margins
$pageMargins = $pdf->getMargins(); // Get all margins as array
$headerMargin = $pageMargins['header']; // Get the header margin
$px2 = $pageWidth - $headerMargin; // Compute x value for second point of line
$p1x = $this->getX();
$p1y = $this->getY();
$p2x = $px2;
$p2y = $p1y; // Use same y for a straight line
$style = array();
$this->Line($p1x, $p1y, $p2x, $p2y, $style);
Links
TCPDF::getMargins()
http://www.tcpdf.org/doc/code/classTCPDF.html#ae9bd660bf5b5e00eea82f1168cc67b5b
TCPDF::getPageWidth()
http://www.tcpdf.org/doc/code/classTCPDF.html#a510ab21d6a373934bcd3bd4683704b7e
Have fun!
Just add some HTML : )
$html ='<hr>';
$pdf->writeHTML($html, true, false, true, false, '');