I am trying to export text to a pdf document using the standard PDFdocument class in android. The code creates a pdf but in the text I write to the PDF, it put mysterious spaces half in words.
Tried using the canvas.drawText option and the drawItemn option.
Both give the same result. The problem code-line is almost at the bottom of the sample code below.
PdfDocument.PageInfo pageInfo = new PdfDocument.PageInfo.Builder(mPageWidth, mPageHeight, pageNr).create();
PdfDocument.Page page = doc.startPage(pageInfo);
Memory memory = mMemoryData.get(pageNr);
Canvas canvas = page.getCanvas();
TextPaint paint = new TextPaint();
paint.setColor(Color.BLACK);
//Header
Yposition = drawItem( canvas,
paint,
18,
true,
Xposition,
Yposition,
memory.getTitle() );
//line
Yposition += 14; //Extra offset to get some space between the text and line
paint.setColor( ContextCompat.getColor(this, R.color.default_Accent) );
canvas.drawLine( Xposition, Yposition, pageInfo.getPageWidth() - Xposition, Yposition, paint );
Yposition += 20;
paint.setColor(Color.BLACK);
paint.setTextSize(10);
// **this is the line that gives the problem**
canvas.drawText(memory.getText(),Xposition, Yposition, paint);
doc.finishPage(page);
The result of this action is:
At first sight this looks ok but if you zoom in a bit or better yet copy/past the text into notepad (or something) you get this:
No w le ts try this
In stead of the problem line, I also tried this:
drawItem( canvas, paint, 10, false, Xposition, Yposition, memory.getText() );
This has some benefits especially with bigger text but other that that it gives the same problem.
Does anybody have an idea how to solve this?
Thanks to the tip from Henry the problem is now solved.
For others having the same problem:
i was close with the setting of the font but "Arial" just doesn't work
This also goes for "Typeface.SANS_SERIF". I kept getting these strange spaces in my text.
Now it put it like below.
paint.setTypeface(Typeface.create( Typeface.MONOSPACE, Typeface.NORMAL));
Not the best looking text markup but it does the trick for now.
Related
What is the right way to know the frame of a word inside of a line in Corona SDK? in other words, I want to add a rect above a specific word, I tried using webview instead and mark tag but the webview keeps flickering on iOS, so the webview solution is canceled.
I have added a rect manually into this word, but what is the best way that I specify a word and know it's frame so I highlight it with the rect, like move the rect to the next word? the font I use is Arial, and it's not monospaced.
local myRect = display.newRect(20,165,32,12.5)
myRect.alpha = 0.5
myRect:setFillColor(1,1,0)
myRect.anchorX = 0
local myString = "Word is highlighted"
local line = display.newText(myString, 0,165, "Arial", 12.5)
line.anchorX = 0
line.x = 20
thanks a lot.
If I were you I would just write additional function for that. Something like:
function highlightedText(pre, high, post, x, y, font, size)
local text = display.newText("", x, y, font, size)
local dx, rectangle = 0
if pre then
local t = display.newText(pre, 0, 0, font, size)
text.text = pre
dx = t.width
-- We need to add line below according to Corona Docs
text.anchorX = 0 text.x = x text.y = y
t:removeSelf()
end
if high then
local t = display.newText(high, 0, 0, font, size)
rectangle = display.newRect(x+dx, y, t.width, t.height)
rectangle:toBack()
text.text = text.text .. high
-- We need to add line below according to Corona Docs
text.anchorX = 0 text.x = x text.y = y
t:removeSelf()
end
if post then
text.text = text.text .. post
-- We need to add line below according to Corona Docs
text.anchorX = 0 text.x = x text.y = y
end
return text, rectangle, dx -- `dx` passed in case of moving whole text along with rectangle
end
local text, rect, _ = highlightedText("The", "word", "is highlighted.", 10, 10, "Arial", 12.5)
rect.alpha = 0.5
rect:setFillColor(1,1,0)
rect.strokeWidth = 3
text:setFillColor(1,1,1)
I'm no expert in Corona but this should work just fine with single-line static text.
Try this one.
local player2 = display.newText("test221234567890", 210, 210 )
player2:setFillColor( 0.6, 0.4, 0.8 )
local myRectangle = display.newRect( player2.x, player2.y, player2.width, player2.height )
myRectangle.strokeWidth = 3
myRectangle:setFillColor( 0.5 )
myRectangle:toBack()
I current have a custom view that I override the onDraw and draw an arc. I want to draw text within this arc. To do this, I use drawTextOnPath and this display curved text at the top of the arc. However, sometimes the text is quite long, so I want to allow it to go on to multiple lines.
I currently use code like this to draw on to multiple lines: -
textView.getPaint().getTextBounds(s, 0,
s.length(), r);
int yOffset=r.height() + textSpacing;
int textStart=0;
int numberOfLines= (int) (r.width()/arcWidth) + 1;
for (int i=0; i < numberOfLines; i ++) {
canvas.drawTextOnPath(s.substring(textStart, textStart + s.length() / numberOfLines),
childHolder.path, 0, yOffset, paint);
yOffset+=r.height() +textSpacing;
textStart=s.length()/numberOfLines;
}
However, this obviously doesn't take into account how wide the text is further down the arc. Is there a way of doing this with using something like staticlayout/dynamiclayout (text does change a lot).
If anyone could point me in either something in android SDK I can use, or the maths to calculate the available width
This bit of code solved my issue: -
PathMeasure pm = new PathMeasure(path, false);
layout = new DynamicLayout(spannableText, spannableText, paint, (int) arcPathMeasure.getLength(), Layout.Alignment.ALIGN_CENTER, 1, 0, true);
Thanks pskink!
I'm working on an Android app utilizing xamarin and the oxyplot library. I ran into a problem where I cannot add multiple lines of text in TextAnnotation.
I tried the following options:
var sb = new StringBuilder();
sb.Append("Line1");
sb.AppendLine(); // which is equal to Append(Environment.NewLine);
sb.Append("\n");
sb.Append("\r\n");
sb.Append(System.Environment.NewLine);
sb.Append("Line2");
and added it like so to the TextAnnotation text object:
var textAnnotation1 = new TextAnnotation();
textAnnotation1.Text = sb.ToString();
textAnnotation1.Background = OxyColors.White;
textAnnotation1.TextColor = OxyColors.Black;
textAnnotation1.FontSize = 18;
textAnnotation1.TextPosition = new DataPoint(4,_vericalLineYaxis);
plotModel.Annotations.Add(textAnnotation1);
but all to avail.
My goal is to have the text appear like so:
Line 1
Line 2
Currently it's appearing as:
Line 1 Line2
Any help would be much appreciated.
Multi-line Annotations is not currently supported on the Android platform.
OxyPlot is invoking Android.Canvas.DrawText and that function does not support text wrapping, it is a fairly low-level primitive drawing routine.
Google's Doc: public void drawText (String text, float x, float y, Paint paint)
If you feel like mod'ing the source, this could be done by using a static layout vs. the current canvas.DrawText.
Something like this would get you started (but is untested):
public void DrawText (string text, float x, float y, Paint paint)
{
TextPaint textPaint = new TextPaint();
StaticLayout textLayout = new StaticLayout(text, textPaint, canvas.getWidth(), Alignment.ALIGN_NORMAL, 1.0f, 0.0f, False);
canvas.Save();
canvas.Translate(x, y);
textLayout.Draw(canvas);
canvas.Restore();
}
FYI: Oxyplot's SVG renderer manually handles multi-line text by string splitting on "\r\n" and rendering a separate element for each line so the same thing could be done for the Android instead of using a StaticLayout (slower performance wise, but easy to mod/test):
var lines = Regex.Split(text, "\r\n");
if (valign == VerticalAlignment.Bottom)
{
for (var i = lines.Length - 1; i >= 0; i--)
{
var line = lines[i];
var size = this.MeasureText(line, fontFamily, fontSize, fontWeight);
this.w.WriteText(p, line, c, fontFamily, fontSize, fontWeight, rotate, halign, valign);
p += new ScreenVector(Math.Sin(rotate / 180.0 * Math.PI) * size.Height, Math.Cos(rotate / 180.0 * Math.PI) * size.Height);
}
}
The goal is to draw a circle having arcs that representing time slices. I have done this:
The problem is that there is a white space between each arch and I want to remove it. Also, the arcs are not aligned. This is my code:
int x = getWidth()/2;
int y = getHeight()/2;
int stroke = 20;
int radiusExternal = 250;
final RectF rect2 = new RectF();
rect2.set(x - radiusExternal, y - radiusExternal, x + radiusExternal, y + radiusExternal);
for (int i = 0; i < modProgram.getListEvents().size(); i++) {
ModEvent event = modProgram.getListEvents().get(i);
Paint paint2 = new Paint();
paint2.setColor(getColorEvent(event));
paint2.setStrokeWidth(stroke);
paint2.setAntiAlias(true);
paint2.setStrokeCap(Paint.Cap.BUTT);
paint2.setStyle(Paint.Style.STROKE);
int initialAngle = getInitialAngle(modProgram, event.getStartEvent());
int sweepAngle = getSweepAngle(modProgram, event, initialAngle);
canvas.drawArc(rect2, initialAngle, sweepAngle, false, paint2);
}
This is probably only a partial answer to deal with the gap between the arc-segments.
Here's a fiddle with javascript: http://jsfiddle.net/oakvLadb/
I've just randomly generated some start- and stop-angles.
The important part lies in the drawing of the arc:
ctx.arc(c.width/2,c.height/2,radius,startAngle,stopAngle+anglePadding);
The anglePadding is there to make sure that a little extra is drawn. When the next segment starts off being drawn from the previous segment's stopAngle, there will be a slit overlapp, making sure no gap is visible.
Next for the poor fit of the arc-segments
When it comes to the fact that it seems like the segments aren't meeting up correctly, the only thing I can think of is that the segments that you're drawing are not those of a perfect circle but an oval, and that's why they're not meeting up correctly. If your rect2 variable doesn't hold data for a perfect square, your segments won't match.
It looks like you do have a perfect square so they should align. Somewhere, there's a rounding error of some kind...
Instead of drawing each Arc next to each other, you can draw larger arcs like layer drawing.
Sorry for my english.
I solve this problem by setting LayerType to LAYER_TYPE_SOFTWARE. like below.
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
export const data = {
labels: ['a', 'b', 'c', 'd'],
datasets: [
{
label: 'Label',
data: [1298, 1798, 2500, 2200],
backgroundColor: [
'#687EEB',
'#FF4B5F',
'#AA71F2',
'#F29741',
],
borderColor: [
'#687EEB',
'#FF4B5F',
'#AA71F2',
'#F29741',
],
borderRadius: [
10,
10,
10,
10,
],
spacing: 20, // i think, this is what you need
borderWidth: 0,
cutout: '80%',
borderAlign: "inner"
},
],
};
I have an app that handels Arabic too, but my Arabic users have a problem that the drawText flip the word .. Arabic must be from right to left. How do I make the canvas drawText from right to left?
See in the picture the highlighted text is the right text its a textView and it's fine. But the canvas DrawText the one in a circle is wrong. It must be from right to left, how do I make the canvas drawText from right to left?
On the canvas just create two points on sides where you want to draw text, and then create path between them. use this method it will work fine
Path path = new Path();
Paint paint = new Paint();
path.moveTo(p2.x, p2.y);
path.lineTo(p1.x, p1.y);
canvas.drawTextOnPath(String.valueOf(txt), path, (float) (c.getWidth() / (2.3)), (float) (c.getHeight()/2 + paint.getTextSize()/1.5), paint);
you can get subString from your string and draw in your canvas:
Paint textPaint = new Paint();
textPaint.setColor(Color.BLACK);
textPaint.setStyle(Paint.Style.FILL_AND_STROKE);
textPaint.setTextSize(20);
textPaint.setTypeface(Typeface.DEFAULT_BOLD);
textPaint.setStrokeWidth(1);
String subString = mString;
float textWidth = textPaint.measureText(mString);
int endOffset = Math.round(rectWidth * (mString.length() - 1) / textWidth);
if (textWidth > rectWidth) {
endOffset =endOffset - 2;
subString = mString.substring(0, endOffset);
subString = subString + "..";
}else{
for(int j=mString.length();j<endOffset+1;j++){
subString+=" ";
}
}
canvas.drawText(subString, padding , (float) (startHeight + eachHeight / 3 + textPaint.getTextSize() / 1.5), textPaint);
in this way we have a same result even in RTL or LTR string .
Make sure that Android emulator that contains the Arabic language, I had the same problem but when I tried the application on an actual mobile device,It solved.
There are no problems in your application in the language, make sure Android emulator supports the Arabic language
If your target device is api level greater than 11 you can use rotateY=180 attribute in TextView element. Also the parent view should set to rotateY = 180.