I'm creating a PDF using iTextSharp for check-printing purposes. My issue is that I cannot get the name/address to print on the check where the little window is on the envelope for the check. The spacing between the address lines is too big. I am setting the line-height in a font tag in the HTML document, but it is not being carried over.
Here is the address part, specifically:
conn.Open();
using (SqlDataReader itemReader = strSQL.ExecuteReader())
{
checksHolder.InnerHtml += "<table cellSpacing=\"0\" cellPadding=\"0\" border=\"0\" width=\"100%\">\n";
while (itemReader.Read())
{
if (i % 3 == 0 && i != 0)
{
checksHolder.InnerHtml += "</table>\n";
checksHolder.InnerHtml += "<!-- pagebreak -->\n";
checksHolder.InnerHtml += "<table cellSpacing=\"0\" cellPadding=\"0\" border=\"0\" width=\"100%\">\n";
f = 0;
}
if (i > 0 && i % 3 != 0)
{
checksHolder.InnerHtml += "<tr><td colspan=\"3\"><br/><br/><br/><br/><br/><br/>";
checksHolder.InnerHtml += "</td></tr>\n";
}
String[] tmpArray = getConsignorInfo(itemReader["check_cs_id"].ToString());
int CheckNum = Int32.Parse(itemReader["check_number"].ToString());
String CheckAmount = itemReader["check_amount"].ToString();
String PayableTo = tmpArray[0];
String Memo = itemReader["check_memo"].ToString();
String name = tmpArray[0];
String address = tmpArray[1];
String city = tmpArray[2];
String state = tmpArray[3];
String zip = tmpArray[4];
Char NBSP = '\u00A0';
checksHolder.InnerHtml += "<tr><td colspan=\"3\"><br/><br/></td></tr>\n";
checksHolder.InnerHtml += "<tr>\n";
//checksHolder.InnerHtml += "<td width=\"5\"></td>\n";
checksHolder.InnerHtml += "<td colspan=\"2\">\n";
checksHolder.InnerHtml += "<font size=\"2\">\n";
checksHolder.InnerHtml += " \n";
checksHolder.InnerHtml += PayableTo + "</font>\n";
checksHolder.InnerHtml += "</td>\n";
checksHolder.InnerHtml += "<td align=\"right\">\n";
checksHolder.InnerHtml += "<font align=\"right\" size=\"2\">" + string.Format("{0:c}", Double.Parse(CheckAmount.ToString())).Replace("$", "") + "</font>\n";
checksHolder.InnerHtml += "</td>\n";
checksHolder.InnerHtml += "</tr>\n";
checksHolder.InnerHtml += "<tr>\n";
checksHolder.InnerHtml += "<td colspan=\"3\">\n";
checksHolder.InnerHtml += " \n";
checksHolder.InnerHtml += "</td>\n";
checksHolder.InnerHtml += "</tr>\n";
checksHolder.InnerHtml += "<tr>\n";
checksHolder.InnerHtml += "<td colspan=\"3\">\n";
checksHolder.InnerHtml += "<font size=\"2\">";
if (wordify(decimal.Parse(CheckAmount.ToString())).Length >= 90)
{
checksHolder.InnerHtml += wordify(decimal.Parse(CheckAmount.ToString()));
}
else
{
string exes = " ";
for (int x = wordify(decimal.Parse(CheckAmount.ToString())).Length; x <= 90; x++)
{
exes += "x";
}
checksHolder.InnerHtml += wordify(decimal.Parse(CheckAmount.ToString())) + exes;
}
checksHolder.InnerHtml += "</font>\n";
checksHolder.InnerHtml += "</td>\n";
checksHolder.InnerHtml += "</tr>\n";
checksHolder.InnerHtml += "<tr>\n";
checksHolder.InnerHtml += "<td colspan=\"2\">\n";
checksHolder.InnerHtml += "<table cellSpacing=\"0\" cellPadding=\"0\" border=\"0\" width=\"100%\">\n";
checksHolder.InnerHtml += "<tr>\n";
checksHolder.InnerHtml += "<td colspan=\"2\"><br/>\n";
checksHolder.InnerHtml += "<font size=\"2\" line-height=\"8p\">" + name + "<br/>\n";
checksHolder.InnerHtml += address + "<br/>\n";
checksHolder.InnerHtml += city + ",\n";
checksHolder.InnerHtml += state + " \n";
checksHolder.InnerHtml += zip + "</font>\n";
checksHolder.InnerHtml += "</td>\n";
checksHolder.InnerHtml += "</tr>\n";
checksHolder.InnerHtml += "<tr>\n";
checksHolder.InnerHtml += "<td colspan=\"3\">\n";
checksHolder.InnerHtml += "<br/></td>\n";
checksHolder.InnerHtml += "</tr>\n";
checksHolder.InnerHtml += "<tr>\n";
checksHolder.InnerHtml += "<td width=\"10\"></td>\n";
checksHolder.InnerHtml += "<td>\n";
checksHolder.InnerHtml += "<font size=\"2\">" + Memo.Substring(0, 50) + "...</font>\n";
checksHolder.InnerHtml += "</td>\n";
checksHolder.InnerHtml += "</tr>\n";
checksHolder.InnerHtml += "</table>\n";
checksHolder.InnerHtml += "</td>\n";
checksHolder.InnerHtml += "<td valign=\"bottom\" width=\"40\">\n";
checksHolder.InnerHtml += "<img valign=\"bottom\" align=\"left\" src=\"images/wesSig.png\" Alt=\"\" /><br/>\n";
checksHolder.InnerHtml += "</td>\n";
checksHolder.InnerHtml += "</tr>\n";
i++;
f++;
}
checksHolder.InnerHtml += "</table>\n";
itemReader.Close();
}
public void CreatePDFDocument(string strHtml)
{
string strFileName = HttpContext.Current.Server.MapPath("printCheck.pdf");
// step 1: creation of a document-object
iTextSharp.text.Rectangle rec = new iTextSharp.text.Rectangle(612, 792);
Document document = new Document(rec);
document.SetMargins(45f, 30f, 55f, 30f);
// step 2:
// we create a writer that listens to the document
var pdfWriter = PdfWriter.GetInstance(document, new FileStream(strFileName, FileMode.Create));
pdfWriter.InitialLeading = 12.5f;
string[] stringSeparators = new string[] { "<!-- pagebreak -->" };
//Response.Write(strHtml);
string[] newString = strHtml.Split(stringSeparators, StringSplitOptions.None);
//HTMLWorker obj = new HTMLWorker(document);
document.Open();
var xmlWorkerHelper = XMLWorkerHelper.GetInstance();
var cssResolver = new StyleAttrCSSResolver();
var xmlWorkerFontProvider = new XMLWorkerFontProvider();
var cssAppliers = new CssAppliersImpl(xmlWorkerFontProvider);
var htmlContext = new HtmlPipelineContext(cssAppliers);
htmlContext.SetTagFactory(Tags.GetHtmlTagProcessorFactory());
PdfWriterPipeline pdfWriterPipeline = new PdfWriterPipeline(document, pdfWriter);
HtmlPipeline htmlPipeline = new HtmlPipeline(htmlContext, pdfWriterPipeline);
CssResolverPipeline cssResolverPipeline = new CssResolverPipeline(cssResolver, htmlPipeline);
XMLWorker xmlWorker = new XMLWorker(cssResolverPipeline, true);
XMLParser xmlParser = new XMLParser(xmlWorker);
int i = 0;
foreach (String currentString in newString) {
if (i > 0)
{
document.NewPage();
}
StringReader sr = new StringReader(currentString);
xmlParser.Parse(sr);
i++;
}
document.Close();
ShowPdf(strFileName);
}
I only have half an inch to put the name/address into. I've tried specifying the line-height with both 8px and just 8 just in case. Nothing worked. Does anyone know how I need to format the HTML to have the line height carried over? Thanks in advance.
I upgraded to itextsharp's xmlworker (http://sourceforge.net/projects/xmlworker/) which allows me to use css and div tags. Margin doesn't work, unfortunately, but padding does, so I was able to do what I needed to do.
Related
How can we center text in PowerShell? WindowWidth doesn't exist apparently, so is there a way somehow to keep the text centered?
We want this output :
*
***
*****
*******
So I wrote
for ($i=1; $i -le 7; $i+=2)
{
write-host("*" * $i)
}
But we get
*
***
*****
*******
function Write-HostCenter { param($Message) Write-Host ("{0}{1}" -f (' ' * (([Math]::Max(0, $Host.UI.RawUI.BufferSize.Width / 2) - [Math]::Floor($Message.Length / 2)))), $Message) }
Write-HostCenter '*'
Write-HostCenter '***'
Write-HostCenter '*****'
I had a bit of fun and wrote some code based on this, that makes a box and center the text inside.
Im sure someone can make a cleaner version, but this do the job just fine :)
# ----------------------------------------------------------------------------------
#
# Script functions
#
# ----------------------------------------------------------------------------------
function MakeTopAndButtom
{
$string = "# "
for($i = 0; $i -lt $Host.UI.RawUI.BufferSize.Width - 4; $i++)
{
$string = $string + "-"
}
$string = $string + " #"
return $string
}
function MakeSpaces
{
$string = "# "
for($i = 0; $i -lt $Host.UI.RawUI.BufferSize.Width - 4; $i++)
{
$string = $string + " "
}
$string = $string + " #"
return $string
}
function CenterText
{
param($Message)
$string = "# "
for($i = 0; $i -lt (([Math]::Max(0, $Host.UI.RawUI.BufferSize.Width / 2) - [Math]::Max(0, $Message.Length / 2))) - 4; $i++)
{
$string = $string + " "
}
$string = $string + $Message
for($i = 0; $i -lt ($Host.UI.RawUI.BufferSize.Width - ((([Math]::Max(0, $Host.UI.RawUI.BufferSize.Width / 2) - [Math]::Max(0, $Message.Length / 2))) - 2 + $Message.Length)) - 2; $i++)
{
$string = $string + " "
}
$string = $string + " #"
return $string
}
function LinesOfCodeInCorrentFolder
{
return (gci -include *.ps1 -recurse | select-string .).Count
}
$MakeTopAndButtom = MakeTopAndButtom
$MakeSpaces = MakeSpaces
$lines = LinesOfCodeInCorrentFolder
# ----------------------------------------------------------------------------------
#
# Run
#
# ----------------------------------------------------------------------------------
$MakeTopAndButtom
$MakeSpaces
$MakeSpaces
$MakeSpaces
$MakeSpaces
CenterText "Lines of .ps1 code in this folder: $($lines)"
CenterText "Press any key to exit"
$MakeSpaces
$MakeSpaces
$MakeSpaces
$MakeSpaces
$MakeTopAndButtom
Read-Host
This gives an output like this:
# ---------------------------------------------------------------------------------------- #
# #
# #
# #
# #
# Lines of .ps1 code in this folder: 6524 #
# Press any key to exit #
# #
# #
# #
# #
# ---------------------------------------------------------------------------------------- #
You can calculate the spaces you need to add and then include them as follows:
$Width = 3
for ($i=1; $i -le 7; $i+=2)
{
Write-Host (' ' * ($width - [math]::floor($i / 2))) ('*' * $i)
}
I need to convert HSL color values to RGB, or to be more precise HSL-values to a System.Drawing.Color object with Powershell.
There are a few solutions in other prog.-languages out there (like LINK). But while it looks simple, I dont get it converted it into Powershell.
Function HSLtoRGB ($H,$S,$L) {
$H = [double]($H / 360)
$S = [double]($S / 100)
$L = [double]($L / 100)
if ($s -eq 0) {
$r = $g = $b = $l
}
else {
if ($l -lt 0.5){
$q = $l * (1 + $s)
}
else {
$q = $l + $s - $l * $s
}
$p = (2 * $L) - $q
$r = (Hue2rgb $p $q ($h + 1/3))
$g = (Hue2rgb $p $q $h )
$b = (Hue2rgb $p $q ($h - 1/3))
}
$r = [Math]::Round($r * 255)
$g = [Math]::Round($g * 255)
$b = [Math]::Round($b * 255)
return ($r,$g,$b)
}
function Hue2rgb ($p, $q, $t) {
if ($t -lt 0) { $t++ }
if ($t -gt 0) { $t-- }
if ($t -lt 1/6) { return ( $p + ($q + $p) * 6 * $t ) }
if ($t -lt 1/2) { return $q }
if ($t -lt 2/3) { return ($p + ($q - $p) * (2/3 - $t) * 6 ) }
return $p
}
HSLtoRGB 63 45 40 # result should be R 145 G 148 B 56
Let's start with the line you're having trouble with translating:
$q = l < 0.5 ? l * (1 + s) : l + s - l * s; #could not translate this line
This construct:
statement ? someValue : anotherValue;
is known as a ternary operation. It basically means:
if(statement){
someValue
} else {
anotherValue
}
So in PowerShell that becomes:
$q = if($l -lt 0.5){
$l * (1 + $s)
} else {
$l + $s - $l * $s
}
Your translation of the inline Hue2Rgb function has two typos that greatly change the calculation:
function Hue2rgb ($p, $q, $t) {
if ($t -lt 0) { $t++ }
if ($t -gt 0) { $t-- } # This condition should be ($t -gt 1)
if ($t -lt 1/6) { return ( $p + ($q + $p) * 6 * $t ) } # The innermost calculation should be ($q - $p) not ($q + $p)
if ($t -lt 1/2) { return $q }
if ($t -lt 2/3) { return ($p + ($q - $p) * (2/3 - $t) * 6 ) }
return $p
}
Regarding the input values, if you take a look at the comments in the original script:
* Assumes h, s, and l are contained in the set [0, 1] and
* returns r, g, and b in the set [0, 255].
So if you want to pass your input values as degrees (hue) and percentages (saturation + luminance), you'll have to handle a conversion to a relative value between 0 and 1:
Function HSLtoRGB ($H,$S,$L) {
$H = [double]($H / 360)
$S = [double]($S / 100)
$L = [double]($L / 100)
# rest of script
}
Lastly, you can use Color.FromArgb() to return an actual Color object:
$r = [Math]::Round($r * 255)
$g = [Math]::Round($g * 255)
$b = [Math]::Round($b * 255)
return [System.Drawing.Color]:FromArgb($r,$g,$b)
I am using ajax to call a method from the server that returns a string data. However I get the following error.
PHP Notice 'yii\base\ErrorException' with message 'Trying to get
property of non-object'
probably this line $first_day=$row->tblStaff2->first_day_service; gives the error.
public function actionGet_loyalty() {
$model = \common\models\staffs\TblStaff::find()->joinWith('tblStaff2')->all();
$string = "<table class='table table-striped'><tr><th>Name</th><th>Number of Years</th></tr>";
foreach ($model as $row) {
$first_day=$row->tblStaff2->first_day_service;
$midname = ucwords($row->midname);
$name = ucwords($row->firstname) . " " . $midname[0] . ". " . ucwords($row->lastname);
$string.="<tr>"
. "<td>" . $name . "</td>"
. "<td>" . $first_day . "</td>"
. "</tr>";
}
$string.="</table>";
return $string;
}
TblStaff relation
public function getTblStaff2() {
return $this->hasOne(TblStaff2::className(), ['staff_id' => 'id']);
}
I have modified your code. Find it below
public function actionGet_loyalty() {
$model = \common\models\staffs\TblStaff::find()->all();
$string = "<table class='table table-striped'><tr><th>Name</th><th>Number of Years</th></tr>";
foreach ($model as $row) {
//What I added
foreach($row->tblStaff2 as $value){
$first_day = $value->first_day_service;
//Here is where it stopped
$midname = ucwords($row->midname);
$name = ucwords($row->firstname) . " " . $midname[0] . ". " . ucwords($row->lastname);
$string.="<tr>"
. "<td>" . $name . "</td>"
. "<td>" . $first_day . "</td>"
. "</tr>";
}
}
$string.="</table>";
return $string;
}
You can remove the comments i added to it when you get it working.
I'm having a problem with my if-else statement. Even if the $key I'm using matches the text in my if statement, the else statement I have at the bottom is also evaluated, so I'm getting multiple values for each $key, which is a problem. What am I doing wrong here?
my $key = $line[0];
if ($key eq 'this_setting') {
my $counter1 = $counter + 1;
my $counter2 = $counter + 2;
$value = join(' ', #line[$counter1..$counter2]);
$my_setting_hash{$key} = $value;
}
if ($key eq 'some_setting_abc') {
my $counter1 = $counter + 1;
my $counter2 = $counter + 2;
$value = join(' ', #line[$counter1..$counter2]);
$my_setting_hash{$key} = $value;
}
if ($key eq 'another_setting_123') {
my $counter1 = $counter + 1;
my $counter3 = $counter + 3;
$value = join(' ', #line[$counter1..$counter3]);
$my_setting_hash{$key} = $value;
}
else {
my $counter1 = $counter + 1;
$value = $line[$counter1];
$my_setting_hash{$key} = $value;
}
Why is this else statement not bypassed if one of my if statements is evaluated?
You need to chain them together with elsif:
my $key = $line[0];
if ($key eq 'this_setting') {
my $counter1 = $counter + 1;
my $counter2 = $counter + 2;
$value = join(' ', #line[$counter1..$counter2]);
$my_setting_hash{$key} = $value;
}
elsif ($key eq 'some_setting_abc') {
my $counter1 = $counter + 1;
my $counter2 = $counter + 2;
$value = join(' ', #line[$counter1..$counter2]);
$my_setting_hash{$key} = $value;
}
elsif ($key eq 'another_setting_123') {
my $counter1 = $counter + 1;
my $counter3 = $counter + 3;
$value = join(' ', #line[$counter1..$counter3]);
$my_setting_hash{$key} = $value;
}
else {
my $counter1 = $counter + 1;
$value = $line[$counter1];
$my_setting_hash{$key} = $value;
}
Otherwise, the first two if statements are independent of the third if/else statement.
As has already been pointed out, you need the keyword elsif
However, another solution is to put your special rules for each key into a hash and so that you can share code:
my %key_length = (
this_setting => 1,
some_setting_abc => 1,
another_setting_123 => 2,
);
my $key = $line[0];
my $index_low = $counter + 1;
my $index_high = $index_low + ($key_length{$key} // 0);
$my_setting_hash{$key} = join ' ', #line[ $index_low .. $index_high ];
Let's say $key's value is 'some_setting_abc'. Your first if does not apply, but the second if does. The third if does not apply either but that one has an else therefore that is executed. As #TedHopp pointed out, you need a single if with chained elsifs and a final else instead.
However, I want to point out that there is a lot of duplication in your code. Life is simpler when you write code a bit more succinctly:
my $key = $line[0];
my $index = $counter + 1;
if (($key eq 'this_setting') or ($key eq 'some_setting_abc')) {
$my_setting_hash{$key} = join ' ', #line[$index .. ($index + 1)];
}
elsif ($key eq 'another_setting_123') {
$my_setting_hash{$key} = join ' ', #line[$index .. ($index + 2)];
}
else {
$my_setting_hash{$key} = $line[$index];
}
I am working on something for learning purposes where I have tackled Collatz using recursion. If you see below I make use of #_ and $_ to keep the for alive.
#!/usr/bin/env perl
sub collatz {
my ($num, $count) = #_;
$count++;
if ($num == 1) {
return $count;
} elsif ($num % 2 == 0) {
return collatz($num/2, $count);
} else {
return collatz($num*3 + 1, $count);
}
}
my $max = 0;
my $saved = 0;
for (1..1000) {
my $length = collatz($_, 0);
print "Num: " . $_ . " Length: " . $length . "\n";
if ($length > $max) {
$max = $length;
$saved = $_;
}
}
print "The longest sequence starts with " . $saved . "\n";
I am trying to use iteration instead of recursion but I just can't think of how to tackle this. I am not after the code in the question, I just want some tips / hints on how to tackle this to get the same result.
I suspect I will need to use a while or an until field.
Any help would be appreciated, again I don't want the exact answer.
Update
Here is my second attempt, which is giving me an error of
Can't return outside a subroutine at answer2.pl line 38.
my $number = 0;
my $counter = 0;
while ($number != 1000) {
$counter++;
if ($number == 1) {
return $counter;
}
elsif ($number % 2 == 0) {
return ($number / 2, $counter);
}
else {
return ($number * 3 + 1, $counter);
}
$number++;
}
print "number" . $number . "counter" . $counter . "\n";
Basically you have tail recursion, which is nice and simple to eliminate.
Instead of collatz calling itself to generate the next step in the sequence, you simply change the variables in-place and loop back to the top.
In its crudest form this would be
sub collatz2 {
my ($num, $count) = #_;
NEXT:
$count++;
if ($num == 1) {
return $count;
}
elsif ($num % 2 == 0) {
$num = $num / 2;
}
else {
$num = $num * 3 + 1;
}
goto NEXT;
}
but it should be written much more nicely than that.
I ended up with this
sub collatz {
my ($num) = #_;
my $count = 1;
while ($num > 1) {
$num = $num % 2 ? $num * 3 + 1 : $num / 2;
++$count;
}
$count;
}
Consider adding the logic that returns when the condition is met in the while.
Spoiler:
my $iter = 0;
while($num != 1){ #do stuff; $iter++ }
Just use a for or while loop with the end condition that your number == 1.
Spoiler:
use strict;
use warnings;
my $max_num = 0;
my $max_steps = 0;
for my $num (1..1000) {
my $steps = 0;
for (my $i = $num; $i != 1; $steps++) {
$i = $i % 2 ? 3 * $i + 1 : $i / 2;
}
print "Num: " . $num . " Length: " . $steps . "\n";
if ($steps > $max_steps) {
$max_num = $num;
$max_steps = $steps;
}
}
print "The longest sequence starts with " . $max_num . "\n";