OpenXml Word ,, Set RTL text along with font size - openxml

i am trying to set a font size and right to left attrib to a word table cell text
but it always take one of them , whenever i set them both it only takes the RTL attrib
here is my code
Paragraph p = cell.Elements<Paragraph>().First();
if (p == null || p.Elements<Run>() == null || p.Elements<Run>().ToArray().Length < 1)
p.Append(new Run());
Run r = p.Elements<Run>().First();
RunProperties RP = r.AppendChild(new RunProperties());
FontSize fontSize = new FontSize();
fontSize.Val = Fontsize.ToString();
RP.AppendChild(fontSize);
RightToLeftText RT = new RightToLeftText()
{
Val = new DocumentFormat.OpenXml.OnOffValue(true)
};
RP.Append(RT);
if (r == null || r.Elements<Text>() == null || r.Elements<Text>().ToArray().Length < 1)
r.Append(new Text());
Text t = r.Elements<Text>().First();
t.Text = New.ToString();
those codes sets the text to the cell as RTL text but with standard font size
if i removed the rtl codes the font size works fine
i'v tried and searched alot with no clue
any tip would be appreciated
thanks in advance

I.v found the answer , i needed to add
FontSizeComplexScript fontSizeComplexScript = new FontSizeComplexScript() { Val = Fontsize.ToString() };
and it worked very well
thank you all
please mark this as answered

Related

How to get value at a point of line extended - TradingView Pine script

Im using the code below to draw a line:
//#version=4
simplesma = sma(close, 14)
var line3 = line.new(bar_index[0], high[0], bar_index, low, extend = extend.right)
line.set_xy1(line3, bar_index[5], simplesma[5])
line.set_xy2(line3, bar_index[3], simplesma[3])
That line has been drawn using 2 points in the history.
And then I use this code to draw a plot
price_point = line.get_price(line3,bar_index)
plot(price_point, title='Price', color=#ffcc00, transp=30)
Im trying to display the value on a label but the following code does not work:
var label3 = label.new(bar_index, high, text = "Value: "+ tostring(price_point, "#.########"), style = label.style_label_lower_left, color=#ffcc00, textcolor=#ff0000)
label.set_xy(label3,bar_index, price_point)
Can you please help me to show it on label ?
The variable price_point is the value at the current bar (bar_index). You don't need to use the function tostring().
Oh I found it.
var label3 = label.new(bar_index, high, text = "", style = label.style_label_lower_left, color=#ffcc00, textcolor=#ff0000)
label.set_xy(label3,bar_index, price_point)
label.set_text(label3, "Value: "+ tostring(price_point, "#.########"))

Email Signature - VBscript for Word, with tables

I'm trying to set a company signature and then implement it with GPO.
Here's what I'm trying to accomplish:
John Hancock | Paralegal | Company, PC
<Logo (to the left of text)> 60 Test Street | PO Box 1389 | Testing, PA 19820
Phone: 555.555.5555| Fax: 555.555.5555 | Email: testing#testing.com (need this hyperlinked)
EDIT: Additional information from comments.
I'm trying to have different attributes (font size, font type, bold, etc) for the text in each particular line within the second row of the table. For example: Test text (this is bold and Calibri) - Test Text 2 (this is not bold and Arial). When I run the script as it stands, I get the logo on the left, in the first column, and a line of text to the right of the logo, in the second column. What I can't figure out is how to add another line of text, on the right, directly underneath the first line, and have that line of text show with different font attributes and such.
Here's the code I have so far:
Set objSysInfo = CreateObject("ADSystemInfo")
Set WshShell = CreateObject("WScript.Shell")
strUser = objSysInfo.UserName
Set objUser = GetObject("LDAP://" & strUser)
strName = objUser.FullName
strFirst = objUser.FirstName
strLast = objUser.LastName
strInitials = objUser.Initials
strOffice = objUser.physicalDeliveryOfficeName
strPOBox = objUser.postOfficeBox
strTitle = objUser.Description
strCred = objUser.info
strStreet = objUser.StreetAddress
strLocation = objUser.l
strPostCode = objUser.PostalCode
strPhone = objUser.TelephoneNumber
strMobile = objUser.Mobile
strFax = objUser.FacsimileTelephoneNumber
strEmail = objUser.mail
strCompany = objUser.Company
Const NUMBER_OF_ROWS = 1
Const NUMBER_OF_COLUMNS = 2
Set objWord = CreateObject("Word.Application")
Set objDoc = objWord.Documents.Add()
Set objSelection = objWord.Selection
Set objEmailOptions = objWord.EmailOptions
Set objSignatureObject = objEmailOptions.EmailSignature
Set objSignatureEntries = objSignatureObject.EmailSignatureEntries
Set objRange = objDoc.Range()
objDoc.Tables.Add objRange, NUMBER_OF_ROWS, NUMBER_OF_COLUMNS
Set objTable = objDoc.Tables(1)
Set objShape = objTable.Cell(1, 1).Range.Hyperlinks.Add(objSelection.InlineShapes.AddPicture("\\eg-fileserver\admin space\signature\logo.jpg"), "http://www.eastburngray.com",,,"")
objTable.Columns(1).Width = 20
objTable.Columns(2).Width = 320
objTable.Cell(1, 2).Range.Font.Bold = True
objTable.Cell(1, 2).Range.Font.Name = "Calibri"
objTable.Cell(1, 2).Range.Font.Size = 10
objTable.Range.ParagraphFormat.SpaceAfter = 0
objTable.Cell(1, 2).Range.Text = strFirst & strInitials & strLast & " | " & strOffice & " | " & strCompany
Set objSelection = objDoc.Range()
objSignatureEntries.Add "Full Signature", objSelection
objSignatureObject.NewMessageSignature = "Full Signature"
objDoc.Saved = True
objWord.Quit
The key to adding text with various formatting in Word is to work with a Range object. You can think of a Range like an invisible Selection, with the major difference that you can have as many Range objects as you need - there can be only one Selection. The trick to changing the formatting is to "collapse" the Range (think of it like pressing the Right- or Left-Arrow keys to a blinking "point", then continuing to type).
Edit Note: Based on bibadia's surmise that this is actually about VBScript and not VBA I've changed the tags in your question and am editing my Answer to fit VBScript. VBScript cannot use Word-specific object declarations and enumerations, so I've removed the "Dim As" and replaced all wdEnum with the Integer equivalent.
Using your code as a starting point, the approach could look something like this:
Dim rngCell
Set rngCell = objTable.Cell(1,2).Range
rngCell.ParagraphFormat.SpaceAfter = 0
rngCell.Text = strFirst & strInitials & strLast & " | " & _
strOffice & " | " & strCompany & vbCr
rngCell.Font.Bold = True
rngCell.Font.Name = "Calibri"
rngCell.Font.Size = 10
rngCell.Collapse 0 'wdCollapseEnd
rngCell.MoveEnd 1, -1 'wdCharacter, -1
rngCell.Text = strPhone & " | " & strFax & " | " & strEmail
rngCell.Font.Bold = False
rngCell.Font.Size = 8
Note 1: The order in which you do things is usually reversed from that when typing as a user: First populate the Range, then apply the formatting.
Note 2: When collapsing at the end of a cell, Word will move the Range position to the beginning of the following cell. Thus, the code moves the point back one character, putting it at the end of the previous (original) cell: rngCell.MoveEnd wdCharacter, -1
Note 3: I added a vbCr at the end of the first rngCell.Text to create the new paragraph within the table cell.

Change sheet cells color onEdit

I figured out how to compare dates in Google Sheets but when I try to enter more dates for some reason all the cells that were green and red become all red. Also how can I make two cells red if only one cell has a date?
Example: In cell D18 the Due date is 4-18-2014 and in cell E18 the cell is blank. I want to make both cells red so I would know that I should find out why is that cell red.
This is the code I have so far:
function onEdit() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = ss.getSheetByName('Copy of Project Sheet 1');
var values1Rule1 = s.getRange('E2:E1000').getValues();
var values2Rule1 = s.getRange('D2:D1000').getValues();
var range3Rule1 = s.getRange('D2:E2');
var color1 = 'Red';
var color2 = 'Green';
for (var row in values1Rule1) {
for (var col in values1Rule1[row]) {
if (values1Rule1[row][col] > values2Rule1[row][col]) s.getRange(s.getRange('D2').offset(row, col, 1, 2).getA1Notation()).setBackgroundColor(color1);
else if (values1Rule1[row][col] < values2Rule1[row][col]) s.getRange(s.getRange('D2').offset(row, col, 1, 2).getA1Notation()).setBackgroundColor(color2);
else s.getRange(s.getRange('D2').offset(row, col, 1, 2).getA1Notation()).setBackgroundColor('white'); }}
};
All you need to do is add this condition as an OR clause in your red condition, e.g.
if (values1Rule1[row][col] > values2Rule1[row][col] || values1Rule1[row][col] === '')
But there's lots of "minor" problems with your code. First of all, you're doing way too many API calls unnecessarily. This is a big performance issue. For example, when you offset, you already have the new range, there's no need to getA1Notation then get the range again, you could do:
s.getRange('D2').offset(row, col, 1, 2).setBackgroundColor(color1);
But that's still two calls, getting D2, then offseting. You could get the desired range at once:
s.getRange(row+1, 4, 1, 2).setBackgroundColor(color1);
I'd go even further and build a matrix of colors and set it all at once after the loop:
s.getRange('D2:E1000').setBackgroundColors(colors);
But even better, inside an onEdit you should only work on what has just being edited, instead of triggering a full recalculation of your colors because the user edited something on another column or another sheet entirely.
I think your code should be something like this:
function onEdit(e) {
var ss = e.source;
var s = ss.getActiveSheet();
if( s.getName() !== 'Copy of Project Sheet 1' ) return; //only interested in one sheet
var r = s.getActiveRange();
var c = r.getColumn();
if( c !== 4 && c !== 5 ) return; //only interested in changes on columns D or E
r = r.offset(0, c === 4 ? 0 : -1, 1, 2);
var v = r.getValues()[0];
r.setBackgroundColor(v[1] === '' || v[1] > v[0] ? 'red' : v[1] < v[0] ? 'green' : 'white');
}
--edit
You can not run this function manually directly, because it needs a parameter that is passed only when it runs automatically. But you can emulate it with a test function, like this:
function testEdit() { onEdit({source:SpreadsheetApp.getActive()}); }

Extract numbers from specific image

I am involved in a project that I think you can help me. I have multiple images that you can see here Images to recognize. The goal here is to extract the numbers between the dashed lines. What is the best approach to do that? The idea that I have from the beginning is to find the coordinates of the dash lines and do the crop function, then is just run OCR software. But is not easy to find those coordinates, can you help me? Or if you have a better approach tell me.
Best regards,
Pedro Pimenta
You may start by looking at more obvious (bigger) objects in your images. The dashed lines are way too small in some images. Searching for the "euros milhoes" logo and the barcode will be easier and it will help you have an idea of the scale and rotation involved.
To find these objects without using match template you can binarize your image (watch out for the background texture) and use the Hu moments on the contours/blobs.
Don't expect a good OCR accuracy on images where the numbers are smaller than 8-10 pixels.
You can use python-tesseract https://code.google.com/p/python-tesseract/ ,it works with your image.What you need to do is to split the result string.I use your https://www.dropbox.com/sh/kcybs1i04w3ao97/u33YGH_Kv6#f:euro9.jpg to test.And source code is below.UPDATE
# -*- coding: utf-8 -*-
from PIL import Image
from PIL import ImageEnhance
import tesseract
im = Image.open('test.jpg')
enhancer = ImageEnhance.Contrast(im)
im = enhancer.enhance(4)
im = im.convert('1')
w, h = im.size
im = im.resize((w * (416 / h), 416))
pix = im.load()
LINE_CR = 0.01
WHITE_HEIGHT_CR = int(h * (20 / 416.0))
status = 0
white_line = []
for i in xrange(h):
line = []
for j in xrange(w):
line.append(pix[(j, i)])
p = line.count(0) / float(w)
if not p > LINE_CR:
white_line.append(i)
wp = None
for i in range(10, len(white_line) - WHITE_HEIGHT_CR):
k = white_line[i]
if white_line[i + WHITE_HEIGHT_CR] == k + WHITE_HEIGHT_CR:
wp = k
break
result = []
flag = 0
while 1:
if wp < 0:
result.append(wp)
break
line = []
for i in xrange(w):
line.append(pix[(i, wp)])
p = line.count(0) / float(w)
if flag == 0 and p > LINE_CR:
l = []
for xx in xrange(20):
l.append(pix[(xx, wp)])
if l.count(0) > 5:
break
l = []
for xx in xrange(416-1, 416-100-1, -1):
l.append(pix[(xx, wp)])
if l.count(0) > 17:
break
result.append(wp)
wp -= 1
flag = 1
continue
if flag == 1 and p < LINE_CR:
result.append(wp)
wp -= 1
flag = 0
continue
wp -= 1
result.reverse()
for i in range(1, len(result)):
if result[i] - result[i - 1] < 15:
result[i - 1] = -1
result = filter(lambda x: x >= 0, result)
im = im.crop((0, result[0], w, result[-1]))
im.save('test_converted.jpg')
api = tesseract.TessBaseAPI()
api.Init(".","eng",tesseract.OEM_DEFAULT)
api.SetVariable("tessedit_char_whitelist", "0123456789abcdefghijklmnopqrstuvwxyz")
api.SetPageSegMode(tesseract.PSM_AUTO)
mImgFile = "test_converted.jpg"
mBuffer=open(mImgFile,"rb").read()
result = tesseract.ProcessPagesBuffer(mBuffer,len(mBuffer),api)
print "result(ProcessPagesBuffer)=",result
Depends python 2.7 python-tesseract-win32 python-opencv numpy PIL,and be sure to follow python-tesseract's remember to .

fpdf multicell issue

how we display fpdf multicell in equal heights having different amount of content
Great question.
I solved it by going through each cell of data in your row that will be multicelled and determine the largest height of all these cells. This happens before you create your first cell in the row and it becomes the new height of your row when you actually go to render it.
Here's some steps to achieve this for just one cell, but you'll need to do it for every multicell:
This assumes a $row of data with a String attribute called description.
First, get cell content and set the column width for the cell.
$description = $row['desciption']; // MultiCell (multi-line) content.
$column_width = 50;
Get the width of the description String by using the GetStringWidth() function in FPDF:
$total_string_width = $pdf->GetStringWidth($description);
Determine the number of lines this cell will be:
$number_of_lines = $total_string_width / ($column_width - 1);
$number_of_lines = ceil( $number_of_lines ); // Round it up.
I subtracted 1 from the $column_width as a kind of cell padding. It produced better results.
Determine the height of the resulting multi-line cell:
$line_height = 5; // Whatever your line height is.
$height_of_cell = $number_of_lines * $line_height;
$height_of_cell = ceil( $height_of_cell ); // Round it up.
Repeat this methodology for any other MultiCell cells, setting the $row_height to the largest $height_of_cell.
Finally, render your row using the $row_height for your row's height.
Dance.
I was also getting same issue when i have to put height equal to three lines evenif i have content of half or 1 and half line, i solved this by checking if in a string no of elements are less than no of possible letters in a line it is 60. If no of letters are less or equal to one line then ln() is called for two empty lines and if no of words are equal to or less than 2 line letters then one ln() is called.
My code is here:
$line_width = 60; // Line width (approx) in mm
if($pdf->GetStringWidth($msg1) < $line_width)
{
$pdf->MultiCell(75, 8, $msg1,' ', 'L');
$pdf->ln(3);
$pdf->ln(3.1);
}
else{
$pdf->MultiCell(76, 4, $msg1,' ', 'L');
$pdf->ln(3.1);
}
Ok I've done the recursive version. Hope this helps even more to the cause!
Take in account these variables:
$columnLabels: Labels for each column, so you'll store data behind each column)
$alturasFilas: Array in which you store the max height for each row.
//Calculate max height for each column for each row and store the value in //////an array
$height_of_cell = 0;
$alturasFilas = array();
foreach ( $data as $dataRow ) {
for ( $i=0; $i<count($columnLabels); $i++ ) {
$variable = $dataRow[$i];
$total_string_width = $pdf->GetStringWidth($variable);
$number_of_lines = $total_string_width / ($columnSizeWidth[$i] - 1);
$number_of_lines = ceil( $number_of_lines ); // Redondeo.
$line_height = 8; // Altura de fuente.
$height_of_cellAux = $number_of_lines * $line_height;
$height_of_cellAux = ceil( $height_of_cellAux );
if($height_of_cellAux > $height_of_cell){
$height_of_cell = $height_of_cellAux;
}
}
array_push($alturasFilas, $height_of_cell);
$height_of_cell = 0;
}
//--END--
Enjoy!
First, it's not the question to get height of Multicell. (to #Matias, #Josh Pinter)
I modified answer of #Balram Singh to use this code for more than 2 lines.
and I added new lines (\n) to lock up height of Multicell.
like..
$cell_width = 92; // Multicell width in mm
$max_line_number = 4; // Maximum line number of Multicell as your wish
$string_width = $pdf->GetStringWidth($data);
$line_number = ceil($string_width / $cell_width);
for($i=0; $i<$max_line_number-$line_number; $i++){
$data.="\n ";
}
Of course you have to assign SetFont() before use GetStringWidth().
My approach was pretty simple. You already need to override the header() and footer() in the fpdf class.
So i just added a function MultiCellLines($w, $h, $txt, $border=0, $align='J', $fill=false).
That's a very simple copy of the original MultiCell. But it won't output anything, just return the number of lines.
Multiply the lines with your line-height and you're safe ;)
Download for my code is here.
Just rename it back to ".php" or whatever you like. Have fun. It works definitely.
Mac
My personal solution to reduce the font size and line spacing according to a preset box:
// set box size and default font size
$textWidth = 100;
$textHeight = 100;
$fontsize = 12;
// if you get text from html div (using jquery and ajax) you must replace every <br> in a new line
$desc = utf8_decode(str_replace('<br>',chr(10),strip_tags($_POST['textarea'],'<br>')));
// count newline set in $desc variable
$countnl = substr_count($desc, "\n");
// Create a loop to reduce the font according to the contents
while($pdf->GetStringWidth($desc) > ($textWidth * (($textHeight-$fontsize*0.5*$countnl) / ($fontsize*0.5)))){
$fontsize--;
$pdf->SetFont('Arial','', $fontsize);
}
// print multicell and set line spacing
$pdf->MultiCell($textWidth, ($fontsize*0.5), "$desc", 0, 'L');
That's all!
A better solution would be to use your own word wrap function, as FPDF will not cut words, so you do not have to rely on the MultiCell line break.
I have wrote a method that checks for every substring of the text if the getStringWidth of FPDF is bigger than the column width, and splits accordingly.
This is great if you care more about a good looking PDF layout, than performance.
public function wordWrapMultiCell($text, $cellWidth = 80) {
$explode = explode("\n", $text);
array_walk($explode, 'trim');
$lines = [];
foreach($explode as $split) {
$sub = $split;
$char = 1;
while($char <= strlen($sub)) {
$substr = substr($sub, 0, $char);
if($this->pdf->getStringWidth($substr) >= $cellWidth - 1) { // -1 for better getStringWidth calculating
$pos = strrpos($substr, " ");
$lines[] = substr($sub, 0, ($pos !== FALSE ? $pos : $char)).($pos === FALSE ? '-' : '');
if($pos !== FALSE) { //if $pos returns FALSE, substr has no whitespace, so split word on current position
$char = $pos + 1;
$len = $char;
}
$sub = ltrim(substr($sub, $char));
$char = 0;
}
$char++;
}
if(!empty($sub)) {
$lines[] = $sub;
}
}
return $lines;
}
This returns an array of text lines, which you could merge by using implode/join:
join("\r\n", $lines);
And what it was used for in the first place, get the line height:
$lineHeight = count($lines) * $multiCellLineHeight;
This only works for strings with a space character, no white spacing like tabs. You could replace strpos with a regexp function then.