2

私はImageMagickとjavaに比較的慣れておらず、WindowsでImageMagick6.3.9Q16とjmagick6.3.9Q16を使用して、円の0度を中心とする円の外側にテキストを表示するプロジェクトに取り組んでいます。PHP MagickWandからこれを行う既存のimagemagickコードを移植していますが、Javaバージョンでは、次の違いのために、円の弧上の各文字の配置が少しずれていると思います。

MagickWandでは、この1行のコードによって円弧上に配置され、フロートx、y座標値、およびフロート角度値(精度を高めるため)を使用して描画ワンド(jmagickのDrawInfoに相当)に注釈を付け、美しく機能します。

MagickAnnotateImage($magick_wand, $drawing_wand, $origin_x + $x, $origin_y - $y, $angle, $character);

ただし、jmagickでは、annotateImageメソッドはDrawInfoという1つの引数しか受け取らないため、他の唯一の選択肢であるcompositeImageメソッドになりました。そのために、各文字を個別の描画情報として描画し、それを透明なpng画像に注釈を付け、rotateImageメソッドでその画像を回転させ、compositeImageを使用してキャンバス画像に配置しますが、compositeImageは処理するだけです。 x&yはint値として(そして角度を考慮しない)、その時点でx&yのdouble値を丸めています(同じ数の小数を取得するため、またはphpバージョンがそれを除外するために使用しているように)容疑者は、キャラクターを円から少しずらした主な理由です。

作業を実行する私のコードは次のとおりです。Articleはフォントファイルへのローカルパスです(例:E:\ WCDE_ENT70 \ worksheet \ Stores \ WebContent \ AdminArea \ CoordsCenterSection \ fonts \ ARIALN.TTF)、nameNumStrはレンダリングする文字列です円(例:SAMUELSON)、fsizeはフォントのポイントサイズ(例:32)、colorStrはフォントの色名(例:黒)、radValは半径(例:120)、poixはx原点開始座標(例: :150)、poiyはy原点開始座標(例:150):

public byte[] getArcedImage(String Article, String nameNumStr, int fsize, String colorStr, int radVal, int poix, int poiy)
{
     try {
            Font f = null;
            try {
                f = Font.createFont(Font.TRUETYPE_FONT, new FileInputStream(Article.replaceAll("%20"," ")));
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (FontFormatException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }

            String fontName = f.getName();
            // Use awt's font metrics since jmagick doesn't have font metrics built in like php magickwand does
            FontMetrics fm = createFontMetrics(new Font(fontName, Font.PLAIN, fsize));
            int strImgW = fm.stringWidth(nameNumStr);
            int strImgH = fm.getHeight();

            String spacerImg = "E:\\WCDE_ENT70\\workspace\\Stores\\WebContent\\AdminArea\\CoordsCenterSection\\images\\600x600.png";

            //Read in large 600 png first as our main canvas
            ImageInfo bi = new ImageInfo(spacerImg);
            MagickImage bmi = new MagickImage(bi);

            // Make canvas image transparent
            bmi.setMatte(true);
            bmi.setBackgroundColor(PixelPacket.queryColorDatabase("#FFFF8800"));

            //defaults or param vals
            final int radius = radVal;
            final int origin_x = poix;
            final int origin_y = poiy;
            final int center_text_on = 0;
            final int charXGeom = 150;
            final int charYGeom = 150;

            double circumference = 0;
            double percentage = 0;
            double degrees = 0;
            double start = 0;
            double current_degree = 0;
            double angle = 0;
            double angle_adjustment = 0;
            double character_center = 0;

            /**
             * Calculate the circumference of the drawn circle and label the image
             * with it.
             */
            circumference = (2 * Math.PI * radius);

            /**
             * Calculate the percentage of the circumference that the string will
             * consume.
             */
            percentage = strImgW / circumference;

            /**
             * Convert this percentage into something practical - degrees.
             */
            degrees = 360 * percentage;

            /**
             * Because the string is centered, we need to calculate the starting point
             * of the string by subtracting half of the required degrees from the
             * anticipated center mark.
             */
            start = center_text_on - (degrees / 2);

            /**
             * Initialize our traversal starting point.
             */
            current_degree = start;

            // 
                        ImageInfo ci = null;
                        MagickImage cmi = null;

                        double x = 0;
                        double y = 0;
                        int finalStrWidth = 0;
                        int charImgW = 0;
                        int charImgH = 0;

                        for (int i=0; i<nameNumStr.length(); i++)
                        {
                                    /**
                                     * Isolate the appropriate character.
                                     */
                                    String charVal = nameNumStr.substring(i, i+1);

                                    charImgW = fm.stringWidth(charVal);
                                    charImgH = strImgH;

                                    ci = new ImageInfo(spacerImg);
                                    cmi = new MagickImage(ci);

                                    // Create Rectangle for cropping character image canvas to final width and height
                                    Rectangle charRect = new Rectangle(0,0,charImgW,charImgH);

                                    // Crop image to final width and height
                                    cmi = cmi.cropImage(charRect);

                                    // Make image transparent
                                    cmi.setMatte(true);
                                    cmi.setBackgroundColor(PixelPacket.queryColorDatabase("#FFFF8800"));

                                    // Set a draw info for each character
                                    DrawInfo cdi = new DrawInfo(ci);

                                    // Set Opacity
                                    cdi.setOpacity(0);

                                    // Set Gravity
                                    cdi.setGravity(GravityType.CenterGravity);

                                    // Set Fill Color
                                    cdi.setFill(PixelPacket.queryColorDatabase(colorStr));

                                    // Set Font Size
                                    cdi.setPointsize(fsize);

                                    // Set Font
                                    cdi.setFont(Article.replaceAll("%20"," "));

                                    // Set the text
                                    cdi.setText(charVal);

                                    // Make the text smoother
                                    cdi.setTextAntialias(true);

                                    // Annotate the draw info to make the character image
                                    cmi.annotateImage(cdi);

                                    // For debug purposes
                                    finalStrWidth += charImgW;

                                    /**
                                     * Calculate the percentage of the circumference that the character
                                     * will consume.
                                     */
                                    percentage = charImgW / circumference;

                                    /**
                                     * Convert this percentage into something practical - degrees.
                                     */
                                    degrees = 360 * percentage;

                                    /**
                                     * Calculate the x and y axis adjustments to make, based on the origin
                                     * of the circle, so we can place each letter.
                                     */
                                    x = radius * Math.sin(Math.toRadians(current_degree));
                                    y = radius * Math.cos(Math.toRadians(current_degree));

                                    // Rotate the character image to the angle
                                    cmi = cmi.rotateImage(angle);

                                    // Composite character image to main canvas image
                                    bmi.compositeImage(CompositeOperator.HardLightCompositeOp, cmi, (int)Math.round((origin_x+x)), (int)Math.round((origin_y-y)));

                                    // Increment the degrees
                                    current_degree += degrees;

                        }

                        bmi = bmi.trimImage();
                        byte[] pi = bmi.imageToBlob(ci);
                        return pi;

            } catch (MagickException e) {
                        e.printStackTrace();
                        return null;
            }
}

private FontMetrics createFontMetrics(Font font)
{
    BufferedImage bi = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB_PRE);
    Graphics g = bi.getGraphics();
    FontMetrics fm = g.getFontMetrics(font);
    g.dispose();
    bi = null;
    return fm;
}

private Rectangle2D createFontRectangle(Font font, String strVal)
{
    BufferedImage bi = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB_PRE);
    Graphics g = bi.getGraphics();
    FontMetrics fm = g.getFontMetrics(font);
    Rectangle2D rect = fm.getStringBounds(strVal, g);
    g.dispose();
    bi = null;
    return rect;
}

それ以来、DrawInfoのsetGeometryメソッドを使用してx、yを設定できることがわかり、jmagick.orgのwikiで見つけた1つの例で、x、yの配置以外にも使用できると思われますが、使用できないことがわかりました。他にどのように使用できるかを示す他の例やドキュメントを見つけてください(角度を指定するためにも)。

私は前向きではありませんが、jmagickのannotateImageの実装は引数として描画情報のみを使用するため、setGeometryが角度を指定する唯一の方法であるように思われます。

DrawInfoのsetGeometryメソッドを使用してx、y、角度を設定する方法を知っている人はいますか?それで私の問題は解決するかもしれないと思います。また、jmagickを使用して、共有したい円の周りにテキストを描画する実例がある場合は、非常に感謝しています。

ありがとう

4

0 に答える 0