PdfSharp: Text height/positioning problem - pdf

Whether I use XTextFormatter or not, I get the same error about the LayoutRectangle having to have a height of 0 or something like this.
new PdfSharp.Drawing.Layout.XTextFormatter(_gfx).DrawString(text
, new PdfSharp.Drawing.XFont(fontName, fontSize, (PdfSharp.Drawing.XFontStyle)fontStyle)
, new PdfSharp.Drawing.XSolidBrush(PdfSharp.Drawing.XColor.FromArgb(foreColour))
, new PdfSharp.Drawing.XRect(new PdfSharp.Drawing.XPoint(xPos, yPos), new PdfSharp.Drawing.XPoint(xLimit, yLimit))
, PdfSharp.Drawing.XStringFormats.Default);
fontStyle is of type System.Drawing.FontStyle
foreColour is of type System.Drawing.Color
I have already predefined _gfx from a PdfPage with Orientation = Landscape, Size = Letter
xPos and yPos are parameters of type double, the same with xLimit and yLimit.
I get the runtime error that the
LayoutRectangle must have a height of
zero (0)...
Per definition a rectangle is meant to have a height, otherwise call it a line! I don't get it!...
I tried with the XGraphics.DrawString() method directly, and I get the same error. It seems that I can't use the LayoutRectangle but have to manage that the text fit within the desired area manually.
var textFont = new PdfSharp.Drawing.XFont(fontName, fontSize, (PdfSharp.Drawing.XFontStyle)fontStyle);
while (xPos + _gfx.MeasureString(text, textFont).Width > xLimit)
textFont = new PdfSharp.Drawing.XFont(fontName, --fontSize, (PdfSharp.Drawing.XFontStyle)fontStyle);
while (yPos + _gfx.MeasureString(text, textFont).Height > yLimit && fontSize > 0)
textFont = new PdfSharp.Drawing.XFont(fontName, --fontSize, (PdfSharp.Drawing.XFontStyle)fontStyle);
_gfx.DrawString(text
, textFont
, new PdfSharp.Drawing.XSolidBrush(PdfSharp.Drawing.XColor.FromArgb(foreColour))
, new PdfSharp.Drawing.XPoint(xPos, yPos));
Though the yPos variable value is the exact same value!
*yPos = Page.Height * .4093, either 40,93% of the page's height.*
Herewith an example of what I try to do:
"Hello World!" "Hello
World!"
And here is what I get:
"Hello World!"
"Hello World!"
And because of different printing area limits and size of the font and the different font style, I can't just write these into one simple sentence including the correct number of spaces.

Quoting error messages exactly helps others to help you.
The error message reads:
DrawString: With XLineAlignment.BaseLine the height of the layout rectangle must be 0.
The text will be aligned at a line, therefore height must be 0. Yes, that's a line.
Use a different alignment if you specify a rectangle.
The TextLayout sample shows how to format text.
The Graphics sample also shows how to layout text (single lines of text, no automatic line breaks; the technique shown in the TextLayout sample handles line breaks automatically using the XTextFormatter class).

While trying to figure out how text positioning works with PdfSharp, I noticed that the DrawString() method writes on top of the Y coordinate that we specify.
If I wish to write at (0, 100)(x, y), this points to the lower-left corner while I thought this was the top-left corner coordinates. As a result, the text string Y coordinate that I should have specified is 100 + string.Height * .6.
PdfDocument pdfDoc = new PdfDocument();
PdfPage pdfPage = new pdfPage();
pdfPage.Size = PageSize.Letter;
pdfPage.Orientation = Orientation.Landscape;
pdfDoc.Pages.Add(pdfPage);
double posX = 0;
double posY = pdfPage.Height * .4093;
string helloString = "Hello"
string worldString = "World!"
XFont helloFont = new XFont("Helvetica", 25, XFontStyle.Regular);
XFont worldFont = new XFont("Helvetica", 270, XFontStyle.Bold);
using(var pdfGfx = XGraphics.FromPdfPage(pdfPage)) { // assuming the default Point UOM
XSize helloStringSize = pdfGfx.MeasureString(helloString, helloFont);
XSize worldStringSize = pdfGfx.MeasureString(worldString, worldFont);
pdfGfx.DrawString(helloString
, helloFont
, XBrushes.Black
, posX
, posY + helloStringSize.Height * .6
, XStringFormats.Default);
pdfGfx.DrawString(worldString
, worldFont
, XBrushes.Black
, pdfPage.Width * .3978
, posY + (worldStringSize.Height + helloStringSize.Height) * .6
, XStringFormats.Default);
}
You'll perhaps wonder why I only add 60% of the string size when I want to get my string written below my Y coordinate? That is because the full height of the font includes somekind of leap on top. So, the computing result will not be what is expected. On the other hand, you don't have to care about a leap if you need one. In my particular case, I don't require leap, so I must take it off the string's height.
If you feel like my explanation needs more accurate details, please feel free to either add them as comments or keep me informed so that I may include them.
Thanks!

Related

Image width & height reversed in visual Studio vb.net

When I view a photograph taken with a digital camera the height is 4000 and the width is 6016, if I take the picture by turning the camera 90 Deg. the height is 6016 and the width is 4000. All is good, if I examine the properties of the image with file explorer(Windows 10) it looks correct for either picture. If I view the picture in Photoshop or picture viewer all looks correct as far as orientation. In my app I use exif to get the width and height it always shows width as 6016 and height as 4000. if I get an image via code:
dim orgimage as bitmap = new bitmap("C:/image/picture.jpg")
the width is always 6016 and the height is always 4000, if I change the 4000 to 3999 via Photoshop the image width and height are correct in my app. Is this a limitation of Visual Studios Visual Basic?
The reason for the difference is that the other applications are manually applying the correction for Exif.Image.Orientation (tag 274).
Just inspect this tag and rotate the bitmap accordingly.
Public Function OrientateImage(img As Image) As Boolean
Const EXIF_ORIENTATION = 274
Dim orientationTag = img.PropertyItems.FirstOrDefault(Function(x) x.Id = EXIF_ORIENTATION)
If orientationTag IsNot Nothing Then
Dim orientation As Short = BitConverter.ToInt16(orientationTag.Value, 0)
Select Case orientation
Case 3
img.RotateFlip(RotateFlipType.Rotate180FlipNone)
Case 6
img.RotateFlip(RotateFlipType.Rotate90FlipNone)
Case 8
img.RotateFlip(RotateFlipType.Rotate270FlipNone)
Case Else
Return False
End Select
End If
Return True
End Function
If you check the orientation property it might help answering/helping your issue with width and height being same when reading photo from Camera output.
Please let us know your findings.
Dim orgimage As bitmap = New Bitmap("C:/image/picture.jpg", True)
Dim otherImage As bitmap = New Bitmap("C:/image/picture2.jpg", True)
'Orientation
Dim exifprop As Integer = orgimage.GetPropertyItem(274).Value(0)
Dim exifprop2 As Integer = otherImage.GetPropertyItem(274).Value(0)
'1 = Horizontal (normal)
'2 = Mirror horizontal
'3 = Rotate 180
'4 = Mirror vertical
'5 = Mirror horizontal and rotate 270 CW
'6 = Rotate 90 CW
'7 = Mirror horizontal and rotate 90 CW
'8 = Rotate 270 CW
EXIF tags,
PropertyItem.Id 274

How to create fishnet in arcgis engine?

I found createfishnet method in arcobject, but it doesn't work.Where is my mistake?
Geoprocessor gp = new Geoprocessor();
gp.OverwriteOutput = true;
ESRI.ArcGIS.DataManagementTools.CreateFishnet fishnet = new ESRI.ArcGIS.DataManagementTools.CreateFishnet();
fishnet.template = buffer_out;
//txtOutputPath2.Text="E:\\program\\shenzhen_science_committee\\sc\\landuse_subway\\shenzhen_subway\\23_net.shp"
fishnet.out_feature_class = txtOutputPath2.Text;
IFeatureCursor cursor1=buffer_out.Search(null,true);
IFeature buffer=cursor1.NextFeature();
IPoint centerPoint =new ESRI.ArcGIS.Geometry.Point();
IArea pArea = buffer.Shape as IArea;
pArea.QueryCentroid(centerPoint);
fishnet.origin_coord = centerPoint;
double height=0;
double width=0;
fishnet.cell_height = 0.1;
fishnet.cell_width = 0.1;
fishnet.number_columns = 50;
fishnet.number_rows = 50;
IGeoProcessorResult results = (IGeoProcessorResult)gp.Execute(fishnet, null);
The result shows wrong HRESULT E_FAIL.
I have tried this in ArcObjects with Java. What I found was that the fishnet could not be generated for area within a particular polygon, as in the ArcMap application. You would have to intersect or use spatial filter on the fishnet output.
Also, try giving all the parameters, even the optional ones like set corner coordinate. If you are using data in a particular projection system, that can be set to the output by setting the template (and this takes only Envelope).
Below is the code that I have used. I wanted the fishnet label as well, so I have enabled it. Make sure you use a space between the x and y coordinate of a point, entered as a String, which is probably the issue here.
GeoProcessor gp = new GeoProcessor();
gp.setOverwriteOutput(true);
IEnvelope aoi = buffer_out.getEnvelope();
CreateFishnet createFishnet = new CreateFishnet();
createFishnet.setOutFeatureClass(tempDir+"/"+fishnetOutput+".shp");
createFishnet.setTemplate(aoi);
createFishnet.setOriginCoord(aoi.getXMin()+" "+aoi.getYMin());
createFishnet.setYAxisCoord(aoi.getXMin()+" "+aoi.getYMax());
createFishnet.setCornerCoord(aoi.getXMax()+" "+aoi.getYMax());
createFishnet.setCellHeight(30.0);
createFishnet.setCellWidth(30.0);
createFishnet.setNumberRows(0);
createFishnet.setNumberColumns(0);
createFishnet.setLabels("LABELS");
createFishnet.setGeometryType("POLYLINE");
gp.execute(createFishnet, null);
I hope you can use this example and apply it to your code.

Unable to add margins in iTextSharp document having images

Requirement:
A large image (dynamic) needs to be split and shown in PDF pages. If image can't be accomodated in one page then we need to add another page and try to fit the remaining portion and so on.
So far I am able to split the image in multiple pages, however it appears that they are completely ignoring the margin values and so images are shown without any margins.
Please see below code:
string fileStringReplace = imageByteArray.Replace("data:image/jpeg;base64,", "");
Byte[] imageByte = Convert.FromBase64String(fileStringReplace);
iTextSharp.text.Image image = iTextSharp.text.Image.GetInstance(imageByte);
float w = image.ScaledWidth;
float h = image.ScaledHeight;
float cropHeight = 1500f;
iTextSharp.text.Rectangle page = new iTextSharp.text.Rectangle(1150f, cropHeight);
var x = page.Height;
Byte[] created;
iTextSharp.text.Document document = new iTextSharp.text.Document(page, 20f, 20f, 20f, 40f); --This has no impact
using (var outputMemoryStream = new MemoryStream())
{
PdfWriter writer = PdfWriter.GetInstance(document, outputMemoryStream);
writer.CloseStream = false;
document.Open();
PdfContentByte canvas = writer.DirectContentUnder;
float usedHeights = h;
while (usedHeights >= 0)
{
usedHeights -= cropHeight;
document.SetPageSize(new iTextSharp.text.Rectangle(1150f, cropHeight));
canvas.AddImage(image, w, 0, 0, h, 0, -usedHeights);
document.NewPage();
}
document.Close();
created = outputMemoryStream.ToArray();
outputMemoryStream.Write(created, 0, created.Length);
outputMemoryStream.Position = 0;
}
return created;
I also tried to set margin in the loop by document.SetMargins() - but that's not working.
You are mixing different things.
When you create margins, be it while constructing the Document instance or by using the setMargins() method, you create margins for when you let iText(Sharp) decide on the layout. That is: the margins will be respected when you do something like document.Add(image).
However, you do not allow iText to create the layout. You create a PdfContentByte named canvas and you decide to add the image to that canvas using a transformation matrix. This means that you will calculate the a, b, c, d, e, and f value needed for the AddImage() method.
You are supposed to do that Math. If you want to see a margin, then the values w, 0, 0, h, 0, and -usedHeights are wrong, and you shouldn't blame iTextSharp, you should blame your lack of insight in analytical geometrics (that's the stuff you learn in high school at the age of 16).
This might be easier for you:
iTextSharp.text.Image image = iTextSharp.text.Image.GetInstance(imageByte);
float w = image.ScaledWidth;
float h = image.ScaledHeight;
// For the sake of simplicity, I don't crop the image, I just add 20 user units
iTextSharp.text.Rectangle page = new iTextSharp.text.Rectangle(w + 20, h + 20);
iTextSharp.text.Document document = new iTextSharp.text.Document(page);
PdfWriter writer = PdfWriter.GetInstance(document, outputMemoryStream);
// Please drop the line that prevents closing the output stream!
// Why are so many people making this mistake?
// Who told you you shouldn't close the output stream???
document.Open();
// We define an absolute position for the image
// it will leave a margin of 10 to the left and to the bottom
// as we created a page that is 20 user units to wide and to high,
// we will also have a margin of 10 to the right and to the top
img.SetAbsolutePosition(10, 10);
document.Add(Image);
document.Close();
Note that SetAbsolutePosition() also lets you take control, regardless of the margins, as an alternative, you could use:
iTextSharp.text.Image image = iTextSharp.text.Image.GetInstance(imageByte);
float w = image.ScaledWidth;
float h = image.ScaledHeight;
// For the sake of simplicity, I don't crop the image, I just add 20 user units
iTextSharp.text.Rectangle page = new iTextSharp.text.Rectangle(w + 20, h + 20);
iTextSharp.text.Document document = new iTextSharp.text.Document(page, 10, 10, 10, 10);
PdfWriter writer = PdfWriter.GetInstance(document, outputMemoryStream);
// Please drop the line that prevents closing the output stream!
// Why are so many people making this mistake?
// Who told you you shouldn't close the output stream???
document.Open();
// We add the image to the document, and we let iTextSharp decide where to put it
// As there is just sufficient space to fit the image inside the page, it should fit,
// But be aware of the existence of a leading; that could create side-effects
// such as forwarding the image to the next page because it doesn't fit vertically
document.Add(Image);
document.Close();

VB.Net make a image in background task using Win2d

Dependency : Win2D
I am trying to generate a Livetile image from background task.
However, the generated PNG file only looks transparent, no single dot is painted at all.
So, I simplified the important code as below to test, yet no result was changed.
I imported Microsoft.Canvas.Graphics(+Effects,+Text),
Dim device As CanvasDevice = New CanvasDevice()
Dim width = 150, height = 150
Using renderTarget = New CanvasRenderTarget(device, width, height, 96)
Dim ds = renderTarget.CreateDrawingSession()
'ds = DrawTile(ds, w, h)
Dim xf As CanvasTextFormat = New CanvasTextFormat()
xf.HorizontalAlignment = CanvasHorizontalAlignment.Left
xf.VerticalAlignment = CanvasVerticalAlignment.Top
xf.FontSize = 12
renderTarget.CreateDrawingSession.Clear(Colors.Red)
ds.Clear(Colors.Blue)
ds.DrawText("hi~", 1, 1, Colors.Black, xf)
renderTarget.CreateDrawingSession.DrawText("hi~", 1, 1, Colors.Black, xf)
Await renderTarget.SaveAsync(Path.Combine(ApplicationData.Current.LocalFolder.Path, "_tile_150x150.png"))
End Using
The file is created, but it's filled with neither Red or Blue. No text at all. It's transparent with only 150x150 pixel canvas.
Is there any problem with the code? or any other reason?
Thanks a lot!
The CanvasDrawingSession ("ds" in your sample) needs to be Closed / Disposed before you call SaveAsync.
You can use "Using ds = renderTarget.CreateDrawingSession()" to do this for you - put the call to SaveAsync after "End Using".
From there you should use the same "ds" rather than call "CreateDrawingSession" multiple times.

Photoshop Automation of alignment of text layer with image

I have never scripted in photoshop before, so I am wondering if this is possible. The following is currently done manually for over than 300 files. The next time round is for 600 files, therefore I am looking into automating it.
Steps:
Make Image Size to 54pixels Hight and 500px Width -- Found that this is doable.
Align Image Left.
Create a text layer and insert text -- Found that this is doable.
Align Text layer 1px to the right of the image.
Trim empty space.
Would appreciate any help and pointers. Thanks.
This script will get you started: Note that in your request you didn't mention what what the original image was going to be and shrinking it to 500 x 54 is going to stretch it one way or another. Step 2, Align the image left, was omitted as you didn't mention what you are aligning this image to. I suspect you are dealing with a large image and what to shrink it down (as long as it's not smaller than 500 x 54) and work from there. I've also omitted stage 4 as I've hard coded the position of the text to be 1 px from the right hand edge (and it vertically centered with Arial font size 18)
Anhyoo.. you should be able to alter the script to your needs.
// set the source document
srcDoc = app.activeDocument;
//set preference units
var originalRulerPref = app.preferences.rulerUnits;
var originalTypePref = app.preferences.typeUnits;
app.preferences.rulerUnits = Units.POINTS;
app.preferences.typeUnits = TypeUnits.POINTS;
// resize image (ignoring the original aspect ratio)
var w = 500;
var h = 54;
var resizeRes = 72;
var resizeMethod = ResampleMethod.BICUBIC;
srcDoc.resizeImage(w, h, resizeRes, resizeMethod)
//create the text
var textStr = "Some text";
createText("Arial-BoldMT", 18.0, 0,0,0, textStr, w-1, 34)
srcDoc.activeLayer.textItem.justification = Justification.RIGHT
//set preference units back to normal
app.preferences.rulerUnits = originalRulerPref;
app.preferences.typeUnits = originalTypePref;
//trim image to transparent width
app.activeDocument.trim(TrimType.TRANSPARENT, true, true, true, true);
// function CREATE TEXT(typeface, size, R, G, B, text content, text X pos, text Y pos)
// --------------------------------------------------------
function createText(fface, size, colR, colG, colB, content, tX, tY)
{
// Add a new layer in the new document
var artLayerRef = srcDoc.artLayers.add()
// Specify that the layer is a text layer
artLayerRef.kind = LayerKind.TEXT
//This section defines the color of the hello world text
textColor = new SolidColor();
textColor.rgb.red = colR;
textColor.rgb.green = colG;
textColor.rgb.blue = colB;
//Get a reference to the text item so that we can add the text and format it a bit
textItemRef = artLayerRef.textItem
textItemRef.font = fface;
textItemRef.contents = content;
textItemRef.color = textColor;
textItemRef.size = size
textItemRef.position = new Array(tX, tY) //pixels from the left, pixels from the top
}
Everything you listed is doable in a script. I suggest you start by reading 'Adobe Intro To Scripting' in your ExtendScript Toolkit program files directory (e.g. C:\Program Files (x86)\Adobe\Adobe Utilities - CS6\ExtendScript Toolkit CS6\SDK\English)