Writing Hindi Fonts with GD Library do not render

2019-01-24 23:42发布

问题:

If I want to write the following text on the image:

दीक्षा शिक्षा क्या क्या हो गया!

Then it does not not give the expected result but instead is printing out text on the picture as below. I have tried almost all the devanagari ttf and unicode fonts available for Hindi.

Here is the code:

$quote="दीक्षा शिक्षा क्या क्या हो गया!";
imagettftext($new_pic, $fontsize, 0, 170, 155-$hidd/2, $color, $font, $quote);

Any help will be very much appreciated.

回答1:

I had the same problem and came up with a solution in PHP using the mangal.ttf font. using this code your Hindi text will display correctly on your image file.

 $text = "की एक विधा" ; 
 $words = explode(" ", $text);
       $words = explode(" ", $text);
for($k = 0; $k < count($words); $k++){

    // detect if the string was passed in as unicode
    $text_encoding = mb_detect_encoding($words[$k], 'UTF-8, ISO-8859-1');

    // make sure it's in unicode
    if ($text_encoding != 'UTF-8') {
        $words[$k] = mb_convert_encoding($words[$k], 'UTF-8', $text_encoding);
        }
 // html numerically-escape everything (&#[dec];)
    $words[$k] = mb_encode_numericentity($words[$k], array (0x0, 0xffff, 0, 0xffff), 'UTF-8');

    $arr = explode("&#", $words[$k]);
for ($i = 0; $i < (count($arr)-1); $i++){

        // interchange the order of "i" vowel
          if($arr[$i] == "2367;") {
            $arr[$i] = $arr[$i-1] . '';
            $arr[$i-1] = "2367;";
            }

        // letter "I" + Nukta forms letter vocalic "L"
          if($arr[$i] == "2311;") {
            if($arr[$i+1] == "2364;") {
                $arr[$i] = "2316;";
                $arr[$i+1] = '';
                }
            }

        // vowel sign vocalic "R" + sign Nukta forms vowel sign vocalic "Rr"
          if($arr[$i] == "2371;") {
              if($arr[$i+1] == "2364;") {
                $arr[$i] = "2372;";
                $arr[$i+1] = '';
                }
            }

        // Candrabindu + sign Nukta forms Om
          if($arr[$i] == "2305;") {
              if($arr[$i+1] == "2364;") {
                $arr[$i] = "2384;";
                $arr[$i+1] = '';
                }
            }

        // letter vocalic "R" + sign Nukta forms letter vocalic "Rr"
          if($arr[$i] == "2315;") {
              if($arr[$i+1] == "2364;") {
                $arr[$i] = "2400;";
                $arr[$i+1] = '';
                }
            }

        // letter "Ii" + sign Nukta forms letter vocalic "LI"
          if($arr[$i] == "2312;") {
              if($arr[$i+1] == "2364;") {
                $arr[$i] = "2401;";
                $arr[$i+1] = '';
                }
            }

        // vowel sign "I" + sign Nukta forms vowel sign vocalic "L"
          if($arr[$i] == "2367;") {
              if($arr[$i+1] == "2364;") {
                $arr[$i] = "2402;";
                $arr[$i+1] = '';
                }
            }

        // vowel sign "Ii" + sign Nukta forms vowel sign vocalic "LI"
          if($arr[$i] == "2368;") {
              if($arr[$i+1] == "2364;") {
                $arr[$i] = "2403;";
                $arr[$i+1] = '';
                }
            }

        // Danda + sign Nukta forms sign Avagraha
          if($arr[$i] == "2404;") {
              if($arr[$i+1] == "2364;") {
                $arr[$i] = "2365;";
                $arr[$i+1] = '';
                }
            }

        // consonant + Halant + Halant + consonant forms consonant + Halant + ZWNJ + consonant
          if($arr[$i] == "2381;") {
              if($arr[$i+1] == "2381;") {
              //$arr[$i+1] = '8204;';
                }
            }

        // consonant + Halant + Nukta + consonant forms consonant + Halant + ZWJ + Consonant
          if($arr[$i] == "2364;") {
              if($arr[$i+1] == "2381;") {
              //$arr[$i] = "2381;";
              //$arr[$i+1] = '8205;';
                }
            }

        }

    $words[$k] = implode('&#',$arr);
    }
$text = implode(" ", $words);

    $img_name = date('dmyhms');
    $image = $img_name.'.png';
    if(file_exists($imagefile)){    

            /*** create image ***/
             $im = @imagecreatefrompng($imagefile);
            /*** create the text color ***/
            $text_color = imagecolorallocate($im, 40, 50, 99);
           /***  set the font file ***/
            $font_file = 'mangal.ttf';
            // Convert HTML entities into ISO-8859-1
           // $text = html_entity_decode($text,ENT_QUOTES, "UTF-8");
            /*** splatter the image with text ***/
             imagefttext($im, 14,0,450, 390, $text_color, $font_file, $text);
            // Save the picture
             imagepng($im,$image);
            }else{
            /*** if the file does not exist we will create our own image ***/
            /*** Create a black image ***/
            $im  = imagecreatetruecolor(150, 30); /* Create a black image */
            /*** the background color ***/
            $bgc = imagecolorallocate($im, 255, 255, 255);
            /*** the text color ***/
            $tc  = imagecolorallocate($im, 0, 0, 0);
            /*** a little rectangle ***/
            imagefilledrectangle($im, 0, 0, 150, 30, $bgc);
            /*** output and error message ***/
            imagestring($im, 1, 5, 5, "Error loading $imagefile", $tc);
        }


回答2:

@SorabhV. Please check my project for devanagari font rendering in Unity3d using Krutidev font. It is working for me in one of our internal projects. The example project is at this link. The idea is to convert the unicode to Krutidev and use the krutidev font.



回答3:

I am not well versed in Hindi but I think the GD library you are using is not using the rules about Hindi language that changes the order in which glyphs are displayed. I don't know what these rules are, but guess they are encoded in the font's GSUB or GPOS tables. GSUB controls the way sequences of glyphs are displayed and GPOS controls the spacing of glyphs. I assume GD library does not process the GPOS or GSUB tables, which is why the order of your string in imagettfext is the order of the glyphs in the string. You may need to implement some string munging code in your script that takes strings, and orders the characters correctly knowing that GD Library will display them in the order they are in the string.

Please use the code below for the following hindi rule

string changeHindiGlyph(string originalText)
{
    string[] words = originalText.Split(new char[]{' '});

    for(int k = 0; k < words.Length; k++)
    {
        if(words[k].Contains("\u093f")) // check if the word contains "i" vowel
        {
            char[] arr = words[k].ToCharArray();
            for (int i = 0; i < arr.Length -1 ; i++)
            {
                //interchange the order of "i" vowel
                if(arr[i] == '\u093f')
                {
                    arr[i] = arr[i-1];
                    arr[i-1] = '\u093f';
                }
            }

            words[k] = new string(arr);
        }
    }

    originalText = string.Join(" ", words);

    return originalText;
}

I have used C# in the above code you can convert it to your scripting language. Similarly you can include more rules in the code so that you get the desired text in the GD library. Hope this solves your problem.