I have created and successfully created my pdf file in php with fpdf
library support.
But the problem is my footer is showing more space.
I want to reduce the space underneath my text. My output is like
this:
Here my code goes:
<?php
require('fpdf/fpdf.php');
class PDF extends FPDF {
function Header() {
$this->SetY(0.208333);
}
function Footer() {
if ($this->footer <> 1)
{
$this->SetY(-15);
}
else
{
echo "bye";
}
}
}
//class instantiation
$pdf=new PDF("l","in",array(8.5,4.17));
$pdf->SetFont('Arial','',8);
$pdf->footer = -15;
//Array2
$datas = array
(
'Address1' => array
(
'Name' => 'Vijaya',
'Area' => 'Valasaravakkam',
'City' => 'Chennai',
),
'Address2' => array
(
'Companyname' => 'Vy Systems',
'Area' => 'Valasaravakkam',
'City' => 'Chennai',
),
'Address3' => array
(
'Companyname' => 'Vy Systems1',
'Area' => 'Valasaravakkam1',
'City' => 'Chennai1',
),
);
//Array2
$datas1 = array
(
'Address4' => array
(
'Name' => 'Jaya',
'Area' => 'Valasaravakkam',
'City' => 'Chennai',
),
);
foreach($datas1 as $address1 => $details1)
{
//pdf_set_text_pos($pdf, 1240, 490);
//$pdf->ln(1);
foreach($datas as $address => $details)
{
$pdf->SetMargins(0,0,0.3);
$pdf->AddPage();
if((is_array($details)) and (is_array($details1)))
{
foreach($details1 as $rows1 => $value1)
{
$pdf->SetX(0.520833);
$pdf->MultiCell(0, 0.2, $value1, 0, "L");
}
$pdf->ln(1.96);
foreach($details as $rows => $value)
{
$pdf->SetX(5);
$pdf->MultiCell(5, 0.2, $value, 0, "L");
}
}
}//end of sub foreach
}//end of main foreach
$pdf->Output();
?>
I didn't follow the code completely, but it seems you're using the Header and Footer methods to set Y and nothing more, expecting that to be enough to correctly position the MultiCells being output outside of the Header and Footer. Maybe so, but the interaction of positioning inside and outside the Header/Footer isn't well defined.
For example, the process may be something like this: Y is calculated for the MultiCell, that trips the footer, the footer changes Y, the MultiCell is output. Is this the original Y, the revised (by the footer Y), or some other value? Absent a precise definition of what happens, you've set up a complex sequence of things that would be very difficult to sort out.
I would suggest vastly simplifying the code. You may find that the automatic header/footer tripping isn't helpful at all. In that case, turn off the auto page break, get rid of the Footer/Header functions, and totally control each page yourself. That way at least you have a clear, reliable model of what's going on.
Related
I am trying to apply collors to my cells using a function which is this:
function color($cell, $color, $find = true){
if ($find){
$color = $this->color_helper($color);
}
$this->sheet->getStyle($cell)->getFill()->applyFromArray(array(
'type' => PHPExcel_Style_Fill::FILL_SOLID,
'startcolor' => array(
'rgb' => $color
)
));
}
colors are defined in the color_picker function and they return something like ''FF0000'for red.
Now the problem is, after I download the file, nothing is changed, its like the original file.
I am using PHPOffice/PHPWord in my Laravel Application. It is used to generate a .docx document with results in tables. This works great for a document of 3 tables with 6 rows, but when there are more rows the document is generated but when opening it the following error occurs:
We're sorry, We can't open (documentname) because we found a problem with its contents.
Details: XML parsing error Location: Part:/word/document.xml, Line: 2, Column 14349.
Now, I have started working on another result page where I would also want to generate a .docx document. This will contain 5 tables, but with 3 rows I get the same XML parsing error but in a different location (Location: Part: /word/document.xml, Line:4, Column:2888). Could someone explain to me whether this is a error in my code, or phpword/words?
I have done some troubleshooting by deleting everything, and slowly adding new rows. I have found the error but how could i fix it. The first two tables are generated good..
$phpWord = new \PhpOffice\PhpWord\PhpWord();
$section = $phpWord->addSection();
$section->addImage('../public/img/2.jpg', array('width' => 230, 'height' => 65, 'alignment' => 'left'));
$section->addText('Project IDs:' . $parameter);
$header =$section->addHeader();
$header->addText('Results Summary');
$section->addLine(
array(
'width' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(16),
'height' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(0),
'positioning' => 'absolute',
)
);
$tableName = 'rStyle';
$phpWord->addFontStyle($tableName, array('italic' => true, 'size' => 12));
$thName = 'tStyle';
$phpWord->addFontStyle($thName, array('bold' => true, 'size' => 9));
$section->addText('General Information Table', $tableName);
$fancyTableStyle = array('borderSize' => 6, 'borderColor' => '999999');
$spanTableStyleName = 'Overview tables';
$phpWord->addTableStyle($spanTableStyleName, $fancyTableStyle);
$table = $section->addTable($spanTableStyleName);
$table->addRow(null, array('tblHeader' => true, 'cantSplit' => true));
$table->addCell(1750)->addText('Project ID',$thName);
$table->addCell(1750)->addText('Description',$thName);
$table->addCell(1750)->addText('Notes',$thName);
foreach ($id_array_explode as $char) {
$table->addRow();
$singlenumber = (int)$char;
$cursor = $collection->find(array("id" => $singlenumber));
foreach ($cursor as $document) {
$table->addCell(1750)->addText($document["project_id"]);
$table->addCell(1750)->addText($document["description"]);
$table->addCell(1750)->addText($document["notes"]);
}
}
$section->addText('
');
$section->addLine(
array(
'width' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(16),
'height' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(0),
'positioning' => 'absolute',
)
);
$section->addText('Input Table', $tableName);
$table1 = $section->addTable($spanTableStyleName);
$table1->addRow(null, array('tblHeader' => true, 'cantSplit' => true));
$table1->addCell(1750)->addText('Project ID',$thName);
$table1->addCell(1750)->addText('#',$thName);
foreach ($id_array_explode as $char) {
$table1->addRow();
$singlenumber = (int)$char;
$cursor = $collection->find(array("id" => $singlenumber));
foreach ($cursor as $document) {
if (is_array($document['input'])) {
foreach ($document['input'] as $samples) {
$table1->addCell(1750)->addText($document["project_id"]);
$table1->addCell(1750)->addText($samples['nr']);
}
}
}
}
$section->addText('
');
$section->addLine(
array(
'width' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(16),
'height' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(0),
'positioning' => 'absolute',
)
);
$section->addText('Output Table', $tableName);
$table2 = $section->addTable($spanTableStyleName);
//// THIS IS WHERE THE ERROR OCCURS!!
$table2->addRow(null, array('tblHeader' => true, 'cantSplit' => true));
$table2->addCell(1750)->addText('ID',$thName);
Thank you!
SOLUTION
Oke, so I have deleted the whole document and added every single sentence separately to see where the error occurred. This led to seeing that the error came from the data which I was getting. It couldn't handle ">" and "&" signs!
So, if you every have this error, check the data which you're printing!
A better solution is to add the following line of code before you do anything with the word document:
PhpOffice\PhpWord\Settings::setOutputEscapingEnabled(true);
This will automatically escape any problematic characters.
Indeed, It comes from your data : you have a XML special character in it and when Word, parses your doc, it doesn't understand.
I solved this problem by using htmlspecialchars(). I'm not sure it is the best way but it works.
Not very familiar with PHPWord, but make sure the encoding of your document and the data you are inserting into it are the same. Used to have the same problem with an old library for creating excel files.
I want to put a link on an ellipsis in the Paginator. When the pagination has 2 ellipsis's the ellipsis must have different link.
My code is:
echo $this->paginator->numbers(array(
'tag' => 'li',
'separator' => '',
'currentTag' => 'a',
'currentClass' => 'active',
'modulus' => 2,
'first' => 1,
'last' => 1,
'ellipsis' => "<li><a href='#' class='hellip'>...</a></li>"
));
So the result I want to create is:
1 ...(link) 6 7 8 ...(link) 12
In short, the Paginator doesn't support what you want it to do and so your only option is to modify the CakePHP source code. Specifically PaginatorHelper.php
First thing you'll need to do is modify the $defaults variable on line 720, and add leftEllipsis and rightEllipsis fields. This means that we can maintain consistent behavior when we don't set these fields in the $options variable.
$defaults = array('tag' => 'span', 'before' => null, 'after' => null,
'model' => $this->defaultModel(), 'class' => null,'modulus' => '8',
'separator' => ' | ', 'first' => null, 'last' => null, 'ellipsis' => '...',
'currentClass' => 'current', 'currentTag' => null, 'leftEllipsis' => null,
'rightEllipsis' => null);
Probably should unset our two new fields too (lines 735 - 738):
unset($options['tag'], $options['before'], $options['after'], $options['model'],
$options['modulus'], $options['separator'], $options['first'], $options['last'],
$options['ellipsis'], $options['class'], $options['currentClass'], $options['currentTag'],
$options['leftEllipsis'], $options['rightEllipsis']
);
The next bit is a tad tricky because it would be nice to be able to specify one of the ellipsis without the other, and in the absence of either, fallback onto whatever the original ellipsis field was set to. But the developers have used the magical extract and compact functions coupled with the first(...) and last(...) functions depending on certain fields being set in the $options parameter.
After line 756 insert the following code to default the $leftEllipsis to whatever $ellipsis is set to:
if(isempty($leftEllipsis)) {
$leftEllipsis = $ellipsis;
}
Next we need to modify what gets passed as the $options parameter to the first(...) function on lines 758 - 761.
if ($offset < $start - 1) {
$out .= $this->first($offset, compact('tag', 'separator', 'class') + array('ellipsis' => $leftEllipsis));
} else {
$out .= $this->first($offset, compact('tag', 'separator', 'class') + array('after' => $separator, 'ellipsis' => $leftEllipsis));
}
You can use this pattern to attack the right ellipsis too.
The proper way to do this is to fork the project on GitHub, make the changes to your version of the code base and create a pull request so you give the developers a chance to integrate your feature into the mainline. This way everyone can benefit from your work!
Good luck!
Imagine this situation:
$component = array(
'type' => 'chimney',
'material' => 'stone'
);
What i would like to do is to add a key/value pair to this array, if a certain condition is met.
$hasMetrics = true;
$component = array(
'type' => 'chimney',
'material' => 'stone',
'metrics' => ($hasMetrics ? array('width' => 60, 'height' => 2000) : false)
);
While this could be used, it will always cause a key called 'metrics' in my array.
Of course, if i don't want that, i could use array_merge() to merge a second array with the first (the second being either an empty array or the desired key/value pair, depending on the condition).
But what i am longing to find out is if there is any way to define this array like above, while taking care of $hasMetrics, without the use of any other means (such as array_merge()) but purely in the actual (first and only) definition of this array.
Like this: (non-applicable, demonstrative example)
$component = array(
'type' => 'chimney',
'material' => 'stone',
($hasMetrics ? array('metrics' => array(
'width' => 60,
'height' => 2000
)) : false)
);
(This, as i understand it, would generate two keys (type and material and then create one keyless value that is, itself, an array containing a key (metrics) and another array as value.)
Can anyone show me some proper approach? Perhaps there is some kind of PHP function available, with special properties (such as list() which is capable of cross-assignment).
EDIT
Perhaps some more clarification is needed, as many answers point out ways to go such as:
Using a followup assignment to a certain key
Filtering the generated array after defining it
While these are perfectly valid ways to extend the array, but i am explicitly looking for a way to do this in one go within the one array definition.
Not with the array defenition itself. I would add it to the array if necessary:
if($hasMetrics) {
$component['metrics'] = array('width' => 60, 'height' => 2000);
}
$hasMetrics = true;
$component = array(
'type' => 'chimney',
'material' => 'stone',
);
if($hasMetrics){
$component['metrics'] = array('width' => 60, 'height' => 2000);
}
Try
$component = array(
'type' => 'chimney',
'material' => 'stone',
'metrics' => $hasMetrics ? array('width' => 60, 'height' => 2000) : ''
);
And after that
$component = array_filter( $component ); // remove if it has '' value
OR
$component = array(
'type' => 'chimney',
'material' => 'stone',
);
if($hasMetrics) {
$component['metrics'] = array('width' => 60, 'height' => 2000);
}
I have a question about IPTC metadata. Is it possible to search images that aren't in a database by their IPTC metadata (keywords) and show them and how would I go about doing this? I just need a basic idea.
I know there is the iptcparse() function for PHP.
I have already written a function to grab the image name, location, and extension for all images within a galleries folder and all subdirectories by .jpg extension.
I need to figure out how to extract the metadata without storing it in a database and how to search through it, grab the relevant images that match the search tag (their IPTC keywords should match) and how to display them. I know at the point that I have the final results (post search) i can echo an imagetag with src="$filelocation"> if i have the final results in an array.
Basically, I am not sure if I need to store all my images into a mysql database and also extract the keywords and store them in the database as well before I can actually search and display the results. Also, if you could guide me to any gallery that already is able to do this, that could help as well.
Thanks for any help regarding this issue.
It is not clear what in particular is giving you problems, but perhaps this will give you some ideas:
<?php
# Images we're searching
$images = array('/path/to/image.jpg', 'another-image.jpg');
# IPTC keywords to values (from exiv2, see below)
$query = array('Byline' => 'Some Author');
# Perform the search
$result = select_jpgs_by_iptc_fields($images, $query);
# Display the results
foreach ($result as $path) {
echo '<img src="', htmlspecialchars($path), '">';
}
function select_jpgs_by_iptc_fields($jpgs, $query) {
$matches = array();
foreach ($jpgs as $path) {
$iptc = get_jpg_iptc_metadata($path);
foreach ($query as $name => $values) {
if (!is_array($values))
$values = array($values);
if (count(array_intersect($iptc[$name], $values)) != count($values))
continue 2;
}
$matches[] = $path;
}
return $matches;
}
function get_jpg_iptc_metadata($path) {
$size = getimagesize($path, $info);
if(isset($info['APP13']))
{
return human_readable_iptc(iptcparse($info['APP13']));
}
else {
return null;
}
}
function human_readable_iptc($iptc) {
# From the exiv2 sources
static $iptc_codes_to_names =
array(
// IPTC.Envelope-->
"1#000" => 'ModelVersion',
"1#005" => 'Destination',
"1#020" => 'FileFormat',
"1#022" => 'FileVersion',
"1#030" => 'ServiceId',
"1#040" => 'EnvelopeNumber',
"1#050" => 'ProductId',
"1#060" => 'EnvelopePriority',
"1#070" => 'DateSent',
"1#080" => 'TimeSent',
"1#090" => 'CharacterSet',
"1#100" => 'UNO',
"1#120" => 'ARMId',
"1#122" => 'ARMVersion',
// <-- IPTC.Envelope
// IPTC.Application2 -->
"2#000" => 'RecordVersion',
"2#003" => 'ObjectType',
"2#004" => 'ObjectAttribute',
"2#005" => 'ObjectName',
"2#007" => 'EditStatus',
"2#008" => 'EditorialUpdate',
"2#010" => 'Urgency',
"2#012" => 'Subject',
"2#015" => 'Category',
"2#020" => 'SuppCategory',
"2#022" => 'FixtureId',
"2#025" => 'Keywords',
"2#026" => 'LocationCode',
"2#027" => 'LocationName',
"2#030" => 'ReleaseDate',
"2#035" => 'ReleaseTime',
"2#037" => 'ExpirationDate',
"2#038" => 'ExpirationTime',
"2#040" => 'SpecialInstructions',
"2#042" => 'ActionAdvised',
"2#045" => 'ReferenceService',
"2#047" => 'ReferenceDate',
"2#050" => 'ReferenceNumber',
"2#055" => 'DateCreated',
"2#060" => 'TimeCreated',
"2#062" => 'DigitizationDate',
"2#063" => 'DigitizationTime',
"2#065" => 'Program',
"2#070" => 'ProgramVersion',
"2#075" => 'ObjectCycle',
"2#080" => 'Byline',
"2#085" => 'BylineTitle',
"2#090" => 'City',
"2#092" => 'SubLocation',
"2#095" => 'ProvinceState',
"2#100" => 'CountryCode',
"2#101" => 'CountryName',
"2#103" => 'TransmissionReference',
"2#105" => 'Headline',
"2#110" => 'Credit',
"2#115" => 'Source',
"2#116" => 'Copyright',
"2#118" => 'Contact',
"2#120" => 'Caption',
"2#122" => 'Writer',
"2#125" => 'RasterizedCaption',
"2#130" => 'ImageType',
"2#131" => 'ImageOrientation',
"2#135" => 'Language',
"2#150" => 'AudioType',
"2#151" => 'AudioRate',
"2#152" => 'AudioResolution',
"2#153" => 'AudioDuration',
"2#154" => 'AudioOutcue',
"2#200" => 'PreviewFormat',
"2#201" => 'PreviewVersion',
"2#202" => 'Preview',
// <--IPTC.Application2
);
$human_readable = array();
foreach ($iptc as $code => $field_value) {
$human_readable[$iptc_codes_to_names[$code]] = $field_value;
}
return $human_readable;
}
If you don't have extracted those IPTC data from your images, each time someone will search, you'll have to :
loop on every images
for each image, extract the IPTC data
see if the IPTC data for the current image matches
If you have more than a couple image, this will be really bad for performances, I'd say.
So, in my opinion, it would be far better to :
add a couple of fields in your database
extract the relevant IPTC data when the image is uploaded / stored
store the IPTC data in those DB fields
search in those DB fields
Or use some search engine like Lucene or Sphinx -- but that is another problem.
It'll mean a bit more work for you right now : you have more code to write...
... But it also means your website will have better chances to survive when there are several images and many users doing searches.