Writing Arabic in pdf using itext - android

I am generating PDF file using itext lib.
I want to write Arabic words.
When i run the below code, The words characters are reverse displayed.
The used code :
PdfContentByte cb = docWriter.getDirectContent();
BaseFont bfBold = BaseFont.createFont("assets/arial.ttf", BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
createHeadings(cb, document.leftMargin(), 70, "السعر الاجمالي: " + tprice + " L.E.");
.
.
.
private void createHeadings(PdfContentByte cb, float x, float y, String text){
cb.beginText();
cb.setFontAndSize(bfBold, 10);
cb.setTextMatrix(x,y);
cb.showText(text.trim());
cb.endText();
}
This image describes the output of the code above:
http://i.stack.imgur.com/OLoLo.jpg

Please take a look at the Ligatures2 example.
Aren't you forgetting this line:
cb.setRunDirection(PdfWriter.RUN_DIRECTION_RTL);
The setRunDirection() method is necessary when you want iText to write the text from right to left and create ligatures where necessary. This method also exists in the context of tables in which case you apply it to a PdfPCell object instead of to a ColumnText object.
Also, I don't understand why you use this String: "السعر الاجمالي: ". Please use the Unicode notation instead (e.g. something like "\u0644\u0648\u0631\u0627\u0646\u0633 \u0627\u0644\u0639\u0631\u0628"), because using a String like yours can create all kinds of confusion regarding encoding and ligatures. Some editors won't use the correct encoding (changing your text into gibberish); some editors will make ligatures (which isn't what iText expects).
For instance, in your case, I don't know Arabic, so I don't know if it's "\u0627\u0644\u0633\u0639\u0631 \u0627\u0644\u0627\u062c\u0645\u0627\u0644\u064a" or "\u064a\u0644\u0627\u0645\u062c\u0627\u0644\u0627 \u0631\u0639\u0633\u0644\u0627" because I don't know if I have to start to read at the glyph with value \u0627 or at the glyph with value \u064a. In any case: iText expects the first "character" in the String to be the first thing that is read by humans.
Please take a look at the ArabicExample example:
The first line is incorrect, because RTL nor Arabic ligatures are supported when using document.add(). The second line is correct (as far as I know: I can't read Arabic) because I used ColumnText.
This is the code I used:
public static final String FONT = "resources/fonts/NotoNaskhArabic-Regular.ttf";
public static final String ARABIC = "\u0627\u0644\u0633\u0639\u0631 \u0627\u0644\u0627\u062c\u0645\u0627\u0644\u064a";
public void createPdf(String dest) throws IOException, DocumentException {
Document document = new Document();
PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(dest));
document.open();
Font f = FontFactory.getFont(FONT, BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
Phrase p = new Phrase("This is incorrect: ");
p.add(new Chunk(ARABIC, f));
p.add(new Chunk(": 50.00 USD"));
document.add(p);
p = new Phrase("This is correct: ");
p.add(new Chunk(ARABIC, f));
p.add(new Phrase(": 50.00"));
ColumnText canvas = new ColumnText(writer.getDirectContent());
canvas.setSimpleColumn(36, 750, 559, 780);
canvas.setRunDirection(PdfWriter.RUN_DIRECTION_LTR);
canvas.addElement(p);
canvas.go();
document.close();
}
I used a Phrase, but you can expect the same result when using a Paragraph (Paragraph extends Phrase). Please clarify if this doesn't answer your question. Take into account that most people on StackOverflow don't understand Arabic, so you have to be very explicit when you ask a question and when you say "it doesn't work". As we don't know Arabic, we don't know how it is supposed to work.

Related

How to read kerning pairs table from TTF file in Android

I am currently drawing text on Canvas while using external (non-standard) font, loaded from TTF file. I want to enable kerning for the text I am displaying.
What I want to know is if there is a possibility to read kerning pairs from typeface using Android API.
What I want to know is if there is a possibility to read kerning pairs from typeface using Android API.
There is no public API to read kerning pairs from a TTF file. However, I pulled the relevant code from Apache FOP and you can read the kerning pairs using this library.
Example usage:
TTFFile file = TTFFile.open(getAssets().open("fonts/font.ttf"));
Map<Integer, Map<Integer, Integer>> kerning = file.getKerning();
You can also retrieve other metadata. Example:
TTFFile ttfFile = TTFFile.open(new File("/system/fonts/Roboto-Regular.ttf"));
String name = ttfFile.getFullName(); // "Roboto Regular"
String family = ttfFile.getSubFamilyName(); // "Regular"
int fontWeight = ttfFile.getWeightClass(); // 400
String copyright = ttfFile.getCopyrightNotice(); // "Font data copyright Google 2014"
I want to enable kerning for the text I am displaying.
See:
How to adjust text kerning in Android TextView?
setLetterSpacing(float)
I was willing to use the parser described above using standard Java on Windows. If anyone wants to do it, one needs to use Rectangle instead of Rect. This is just a minor conversion. I also eliminated the directory jaredrummler because it was a bit too long (I kept the copyright comments in the beginning of the files, though). But there are two TTFFile classes in this parser. This code:
TTFFile file;
File ttf = new File("C:\\Windows\\Fonts\\calibri.ttf" );
try { file = TTFFile.open(ttf); }
catch (IOException e) {e.printStackTrace(); }
Map<Integer, Map<Integer, Integer>> kerning = file.getKerning();
Only works if you import the correct class file:
import com.fontreader.truetype.TTFFile;
Finally, the code works but the kerning pairs returned don't work with the paths you convert using:
void vectorize(Path2D.Float path, String s) {
PathIterator pIter;
FontRenderContext frc = new FontRenderContext(null,true,true);
GlyphVector gv;
Shape glyph;
gv = font.createGlyphVector(frc, s);
glyph = gv.getGlyphOutline(0);
pIter = glyph.getPathIterator(null);
while (!pIter.isDone()) {
switch(pIter.currentSegment(points)) {
case PathIterator.SEG_MOVETO:
path.moveTo(points[0], points[1]);
break;
case PathIterator.SEG_LINETO :
path.lineTo(points[0], points[1]);
break;
case PathIterator.SEG_QUADTO :
path.quadTo(points[0], points[1], points[2], points[3]);
break;
case PathIterator.SEG_CUBICTO :
path.curveTo(points[0], points[1], points[2], points[3], points[4], points[5]);
break;
case PathIterator.SEG_CLOSE :
path.closePath();
}
pIter.next();
}
}
And lengths recovered by lens in the following code:
double interchar = fontsize * 0.075;
int size = '}' - ' ' + 1;
Path2D.Float[] glyphs = new Path2D.Float[size];
double[] lens = new double[size];
String chars[] = new String[size];
int i; char c;
char[] s = { '0' };
for (i = 0, c = ' '; c <= '}'; c++, i++) { s[0] = c; chars[i] = new String(s); }
for (i = 0; i < size; i++) {
vectorize(glyphs[i] = new Path2D.Float(), chars[i], tx[i], 0f);
lens[i] = glyphs[i].getBounds2D().getWidth() + interchar;
}
Just to be clear, I display the glyphs using fill in Graphics2D and I translate using the lengths above added to the kerning displacements returned by the library Apache FOP as suggested above, but the result is horrible. The fontsize is standard 1000 as suggested in this discussion and interchar results in 75, after multiplying by the font size. All this seems correct but my manual kerning pairs look far much better than using the kerning pairs from the ttf file.
Is there anyone trained with this library to be able to tell how we are supposed to use these kerning pairs?
Sorry for diverting slightly from the original question but this might complete the information since once one reads the kerning pairs how one uses them correctly on either Windows or Android?

Rupee symbol is not showing in android

Friends am using itextpdf-5.3.4.jar for creating pdf. For showing rupee symbol am using custom font. I tried arial.ttf,arialbd.ttf both this font but no luck rupee symbol is not showing. For showing the rupee symbol i have followed these links but it's not working for me.
How to display indian rupee symbol in iText PDF in MVC3. This is the code I have used.
BaseFont rupee =BaseFont.createFont( "assets/arial .ttf", BaseFont.IDENTITY_H,BaseFont.EMBEDDED);
createHeadings(cb,495,60,": " +edt_total.getText().toString(),12,rupee);
private void createHeadings(PdfContentByte cb, float x, float y, String text, int size,BaseFont fb){
cb.beginText();
cb.setFontAndSize(fb, size);
cb.setTextMatrix(x,y);
cb.showText(text.trim());
cb.endText();
}
Please help me guys.
In the comment section, Funkystein wrote that the problem you describe is typical when
you are using a font which doesn't have that glyph. or
you aren't using the right encoding.
I have written an example that illustrates this: RupeeSymbol
public static final String DEST = "results/fonts/rupee.pdf";
public static final String FONT1 = "resources/fonts/PlayfairDisplay-Regular.ttf";
public static final String FONT2 = "resources/fonts/PT_Sans-Web-Regular.ttf";
public static final String FONT3 = "resources/fonts/FreeSans.ttf";
public static final String RUPEE = "The Rupee character \u20B9 and the Rupee symbol \u20A8";
public void createPdf(String dest) throws IOException, DocumentException {
Document document = new Document();
PdfWriter.getInstance(document, new FileOutputStream(DEST));
document.open();
Font f1 = FontFactory.getFont(FONT1, BaseFont.IDENTITY_H, BaseFont.EMBEDDED, 12);
Font f2 = FontFactory.getFont(FONT2, BaseFont.IDENTITY_H, BaseFont.EMBEDDED, 12);
Font f3 = FontFactory.getFont(FONT3, BaseFont.IDENTITY_H, BaseFont.EMBEDDED, 12);
Font f4 = FontFactory.getFont(FONT3, BaseFont.WINANSI, BaseFont.EMBEDDED, 12);
document.add(new Paragraph(RUPEE, f1));
document.add(new Paragraph(RUPEE, f2));
document.add(new Paragraph(RUPEE, f3));
document.add(new Paragraph(RUPEE, f4));
document.close();
}
The RUPEE constant is a String that contains the Rupee character as well as the Rupee symbol: "The Rupee character ₹ and the Rupee symbol ₨".
The characters are stored as Unicode values, because if we store the characters otherwise, they may not be rendered correctly. For instance: if you retrieve the values from a database as Winansi, you will end up with incorrect characters.
I test three different fonts (PlayfairDisplay-Regular.ttf, PT_Sans-Web-Regular.ttf and FreeSans.ttf)
and I use IDENTITY_H as encoding three times. I also use WINANSI a fourth time to show that it goes wrong if you do.
The result is a file named rupee.pdf:
As you can see, the first two fonts know how to draw the Rupee character. The third one doesn't. The first two fonts don't know how to draw the Rupee symbol. The third one does. However, if you use the wrong encoding, none of the fonts draw the correct character or symbol.
In short: you need to find a font that knows how to draw the characters or symbols you need, then you have to make sure that you are using the correct encoding (for the String as well as the Font).
You can download the full sample code here.

libgdx FreeTypeFontGenerator: how to generate a string with TTF font file correctly?

I use following code to generate font in libgdx:
class XFont {
private FreeTypeFontGenerator _generator;
public BitmapFont getFont(String str,int size) {
if (_generator == null) {
_generator = new FreeTypeFontGenerator(Gdx.files.internal("win/msyh.ttf"));
//_generator = new FreeTypeFontGenerator(Gdx.files.absolute("/system/fonts/DroidSansFallback.ttf"));
Gdx.app.log(TAG, "generator"+_generator.toString());
}
return _generator.generateFont(size, str, false);
}
}
when I call :
XFont x = new XFront();
x.getFont("iiiis",11);
raise exception:
java.lang.RuntimeException: Key with name 'i' is already in map.
I work with chinese and japanese.
The generateFont() method takes a string containing the unique characters you'd like to be in the generated font. You then use that generated font to draw a string containing those characters - via font.draw(batch, string, x, y).
Note: I'd recommend not generating a new BitmapFont every time you want to draw a String, but instead generate a font with all the characters you will likely use then reuse that BitmapFont.
First, _generator.generateFont(size, str, false) take str as a string that contains all unique characters that you want to generate bitmap font. I preferred use charset for this. Then you should generate a bitmap font just once. Example:
// in your constants
public static final String FONT_CHARSET = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ 1234567890,./;'[]\\`~!##$%^&*()_+{}|:\"<>?";
// in your resource loading code
FreeTypeFontGenerator fontGenerator = new FreeTypeFontGenerator(Gdx.files.internal("myFont.ttf"));
BitmapFont myFont = fontGenerator.generateFont(24, FONT_CHARSET, false);
fontGenerator.dipose(); // remember to dispose the generator after used
The FONT_CHARSET contains all characters in the keyboard, I think it is enough for English texts.

Inline images with Text in android

I'm attempting to download webpages for a user to view later. So far, I've downloaded the html, and the images. I can get the HTML to show up nicely formatted, but I cannot get the images to inline.
The code I'm using so far:
This is my method to get the article.
MyImageGetter mig = new MyImageGetter(this, urlId);
Spanned span = Html.fromHtml(contents[1], mig, null);
contents[1] = span.toString();
titleView.setText(contents[0]);
content.setText(contents[1]);
contents[] is an array that contains two strings. contents[0] is a simple string, contents[1] is a string with HTML markup.
MyImageGetter:
public class MyImageGetter implements Html.ImageGetter{
String urlId = null;
Context c = null;
public MyImageGetter(ArticleViewer articleViewer, String urlId2) {
c = articleViewer;
urlId = urlId2;
}
public Drawable getDrawable(String source) {
String[] brokenUrl = source.split("/");
String imgName = brokenUrl[brokenUrl.length-1];
File image = new File("/data/data/com.theHoloDev.Reader/Offline/" + urlId + "/" + imgName);
Log.w("MyApp", image.getAbsolutePath());
Bitmap bm = BitmapFactory.decodeFile(image.getAbsolutePath());
Drawable d = new BitmapDrawable(c.getResources(), bm);
return d;
}
}
When I have it log image.getAbsolutePath() it comes up with a file that exists in ddms. The Text content is there perfectly, but there are still little black boxes that say obj in each image. I had thought a textview would still be able to display images in that fashion, but either I'm doing something wrong, or there is another way to do this.
What is your desired end result? It is confusing to see that you are displaying html but you want the user to see the page... without html or did you do that for debugging? I assume the users will not see the html but rather the the page itself. In this case, I would go for a webview.
http://developer.android.com/reference/android/webkit/WebView.html
I don't think the text view is meant to be used like you are using it.
Good luck.
I figured it out. Instead of:
Spanned span = Html.fromHtml(contents[1], mig, null);
contents[1] = span.toString();
content.setText(contents[1]);
I need:
Spanned span = Html.fromHtml(contents[1], mig, null);
content.setText(span);
I was running into problems setting span to string.

How to read word by word from file?

Could anybody post here some code how can I read word by word from file? I only know how to read line by line from file using BufferedReader. I'd like if anybody posted it with BufferedReader.
I solved it with this code:
StringBuilder word = new StringBuilder();
int i=0;
Scanner input = new Scanner(new InputStreamReader(a.getInputStream()));
while(input.hasNext()) {
i++;
if(i==prefNamePosition){
word.append(prefName);
word.append(" ");
input.next();
}
else{
word.append(input.hasNext());
word.append(" ");
}
}
There's no good way other than to read() and get a character at a time until you get a space or whatever criteria you want for determining what a "word" is.
If you're trying to replace the nth token with a special value, try this:
while (input.hasNext()) {
String currentWord = input.next();
if(++i == prefNamePosition) {
currentWord = prefName;
}
word.append(currentWord);
word.append(" ");
}
Another way is to employ a tokenizer (e.g. in Java) and using the delimiter space character (i.e. ' '). Then just iterate through the tokens to read each word from your file.
You can read lines and then use splits. There is no clear definition of word but if you want the ones separated by blank spaces you can do it.
You could also use regular expressions to do this.

Categories

Resources