Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Right to Left Languages (like Arabic). #686

Closed
oorabi opened this issue Oct 1, 2015 · 19 comments · Fixed by #2653
Closed

Right to Left Languages (like Arabic). #686

oorabi opened this issue Oct 1, 2015 · 19 comments · Fixed by #2653
Labels

Comments

@oorabi
Copy link

oorabi commented Oct 1, 2015

Words in (RTL Languages) are improperly displayed on the Canvas).

@oorabi
Copy link
Author

oorabi commented Oct 3, 2015

In NodeParser.prototype.paintText = function(container) {
I commented the !hasUnicode, so the problem was solved and the arabic characters appear as continous.
the main problem in arabic was that, textList was set as splitted characters instead of splitted words.

var textList = (!this.options.letterRendering || noLetterSpacing(container))
//&& !hasUnicode(container.node.data)
? getWords(characters)
: characters.map(function (character) {
return punycode.ucs2.encode([character]);
});

@mese79
Copy link

mese79 commented Oct 25, 2015

I had the same problem on 0.5.0-alpha1 which was solved by replacing !hasUnicode by hasUnicode .
Thanks.

@behzadev
Copy link

behzadev commented Nov 2, 2015

@oorabi thanks, fixed the problem by removing "!hasUnicode" on line 2321, html2canvas 0.5.0-alpha1

@nagromnortara
Copy link

Just to share some of my findings.

As oorabi already mentioned the problem with Arabic (and some other languages) is that they have logical (char-by-char) presentation and visual presentation (where following chars may effect to the presentation of previous chars). This issue can be solved by removing the check !hasUnicode, since that forced anything that contains non ASCII chars to be handled char by char.

But that is not the whole problem, since they do mix ASCII with the Arabic, for example colons, brackets etc. But those should be presented at the left side of the word that they are following. In order to do this we need to split the ASCII chars to own words. I did this by checking if the script category changes (i didn't care about others than Arabic for now).

    var previousScriptCategory = null;

    while(characters.length) {
        if(previousScriptCategory == null) {
            previousScriptCategory = getUtf8ScriptCategory(characters[i]);
        }
        if (isWordBoundary(characters[i]) === onWordBoundary || getUtf8ScriptCategory(characters[i]) !== previousScriptCategory) {
            word = characters.splice(0, i);
            if (word.length) {
                words.push(window.html2canvas.punycode.ucs2.encode(word));
            }
            onWordBoundary =! onWordBoundary;
            i = 0;
            previousScriptCategory = null;
        } else {
            i++;
        }
        ...
function getUtf8ScriptCategory(char) {
    if(char >= 0x0600 && char <= 0x06ff) {
        return "arabic";
    } else {
        return "default"
    }
}

But it doesn't end there. We still have problem of brackets, sure the previous splits them to separate words, but we are still rendering from right to left so they get rendered the wrong way. So my take was to make another hack for them.

    //If right-to-left, we should swap brackets
    for(var j = 0; j < words.length; j++) {
        for(var k = 0; k < words[j].length; k++) {
            if(words[j][k] == "(" && isRtl(words[j+1])) words[j] = words[j].replaceAt(k,")")
            else if(words[j][k] == ")" && isRtl(words[j-1])) words[j] = words[j].replaceAt(k,"(")
            else if(words[j][k] == "[" && isRtl(words[j+1])) words[j] = words[j].replaceAt(k,"]")
            else if(words[j][k] == "]" && isRtl(words[j-1])) words[j] = words[j].replaceAt(k,"[")
            else if(words[j][k] == "{" && isRtl(words[j+1])) words[j] = words[j].replaceAt(k,"}")
            else if(words[j][k] == "}" && isRtl(words[j-1])) words[j] = words[j].replaceAt(k,"{")
        }
    }
    return words;
function isRtl(string) {
    if((/[\u0600-\u06ff]/).test(string)) { //Arabic
        return true;
    }
    return false;
}

This is really a hacky way around the issue, but I hope someone can propose more proper way to handle these issues.

@sina-mirhejazi
Copy link

+1 Same issue here. Please fix this

@vali-mint
Copy link

vali-mint commented Sep 22, 2016

n-a-g-r-o-m's solutions is very good, but I had to make some modifications to work on my project.

// If right-to-left, we should swap brackets
for(var j = 0; j < words.length; j++) {
        for(var k = 0; k < words[j].length; k++) {
            if     (words[j][k] == "(" /*&& isRtl(words[j+1])*/) words[j] = replaceAtIndex(words[j],k,")")
            else if(words[j][k] == ")" /*&& isRtl(words[j-1])*/) words[j] = replaceAtIndex(words[j],k,"(")
            else if(words[j][k] == "[" /*&& isRtl(words[j+1])*/) words[j] = replaceAtIndex(words[j],k,"]")
            else if(words[j][k] == "]" /*&& isRtl(words[j-1])*/) words[j] = replaceAtIndex(words[j],k,"[")
            else if(words[j][k] == "{" /*&& isRtl(words[j+1])*/) words[j] = replaceAtIndex(words[j],k,"}")
            else if(words[j][k] == "}" /*&& isRtl(words[j-1])*/) words[j] = replaceAtIndex(words[j],k,"{")
        }
    }
function replaceAtIndex(s, index, char) {
    s = s.substr(0, index) + char + s.substr(index + 1);
    return s;
}

@wexter1
Copy link

wexter1 commented Dec 27, 2016

@vali-mint I am using 0.4.1 and having the same issue of brackets & Commas, I tried the code above but i cant make it done. can you tell me where exactly i need to put this code?

@hadihashem
Copy link

hadihashem commented Aug 24, 2018

Hi @n-a-g-r-o-m
Do you have a solution on the latest version v1.0.0-alpha.12?
I'm struggeling from a while
Many thanks
Regards

@nagromnortara
Copy link

@hadihashem Sorry I drop using this long time ago, so unfortunately I can't help.

@mohafouad
Copy link

same problem with me Arabic language :( any help please

@mohafouad
Copy link

@hadihashem Do you have a solution ?

@mohafouad
Copy link

@oorabi did you find solution ?

@EdiWang
Copy link

EdiWang commented Oct 30, 2019

I have a text overlapping problem when Arabic content is set to RTL. I notice this issue has been opened for 4 years. Any update on this?

@abdelaziz321
Copy link

@EdiWang did you find any solution?
all the solutions I found are for previous versions which have problems in other ways 😕

@EdiWang
Copy link

EdiWang commented Nov 11, 2019

@abdelaziz321 unfortunately, no. Currently, I have to let my users for Arabic content use screenshot extension like FireShot to work around the issue, this is very awkward.

@abdelaziz321
Copy link

abdelaziz321 commented Nov 12, 2019

I really don't know why this worked, but It did when using these dependencies together:

"dependencies": {
    "html2canvas": "^1.0.0-alpha.12",
    "js-html2pdf": "^1.1.4",
    "jspdf": "^1.5.3"
}

and in one of my components:

<template>
  <v-card>
    <v-toolbar dark color="accent" dense flat>
      <v-toolbar-title class="white--text">طباعة الكارنيه</v-toolbar-title>
    </v-toolbar>

    <v-card-text class="pa-4">
      <div id="card-to-be-printed" style="position: relative; width: 9cm">
        <div class="mb-5 pb-5">
          <img src="@/assets/images/card/front.png" alt="front card" style="width: 100%">
          <p
            class="student-name"
          >{{ student.name }}</p>
   
          <barcode
            class="student-barcode"
            :value="student.barcode"
            format="CODE128"
          >خطأ في الباركود</barcode>
        </div>
        <img src="@/assets/images/card/back.png" alt="back card" style="width: 100%">
      </div>
    </v-card-text>

    <v-card-actions style="background-color: #f7f7f7">
      <v-spacer></v-spacer>
      <v-btn color="accent" class="white--text" elevation="1" @click.native="download(student)">تحميل pdf</v-btn>
    </v-card-actions>
  </v-card>
</template>


<script>
import Html2Pdf from "js-html2pdf";

export default {
  name: 'PrintCardDialog',

  methods: {
    download(student) {
      const card = document.querySelector('#card-to-be-printed');

      card.style.fontFamily = 'Cairo';

      const options = {
        margin: [15, 20, 15, 20],
        filename: `student_${student.id}.pdf`,
        image: { type: 'png' },
        html2canvas: { logging: false },
        jsPDF: { orientation: 'p' }
      };

      let exporter = new Html2Pdf(card, options);

      exporter.getPdf(true).then(pdf => {
          this.$emit('success', student);
      });      
    }
  }
};
</script>

and here is the result

Screenshot from 2019-11-12 06-46-11

hope it works for you @EdiWang

@MohammedYoussefSoliman
Copy link

I fixed this issue simply by changing the css root direction * {direction: rtl}

@mAbdelazem
Copy link

@MohammedYoussefSoliman can you please give more details!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.