Русский English Тэги View Sergey Zolotaryov's profile on LinkedIn Вход
О борьбе с java.awt.HeadlessException
Постоянная ссылка 02-04-2008 anydoby java

Недавно на мой сайт напали нехорошие дяди, которые писали в комменты всякую чушь. Руками удалять я их задолбался и решил поставить проверенную штуку captcha. На Java написана замечательная генерилка подобных милых картинок, называется SimpleCaptcha. Можно сконфигурировать и расширить генерилку до неузнаваемости, и пользоваться ей предельно просто.

Вот только досадное обстоятельство - она не работает на headless серверах - то есть без видеокарты и монитора. А так как у меня именно такой сервер и отказываться от этой замечательной либы я не хотел, то пришлось подумать, как проблему решить.

Для начала, -Djava.awt.headless=true не сработало. Пришлось изучать код. Оказалось, что все до банального просто - автор при генерации картинки зачем-то лезет в GraphicsEnvironment и тащит оттуда GraphicsConfiguration, которую нигде не использует и которая для рисования в BufferedImage совсем не нужна - картинка-то находится в памяти, и для манипуляций с ней совершенно не нужна видеокарта. Написал я вот такой простенький рендерер, который по-сути copypaste с оригинала, но без обращения к конфигурации видео:


package com.anydoby.commons.web;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.font.FontRenderContext;
import java.awt.font.GlyphVector;
import java.awt.image.BufferedImage;
import java.util.Properties;
import java.util.Random;

import nl.captcha.servlet.Constants;
import nl.captcha.text.WordRenederer;
import nl.captcha.util.Helper;

public class HeadlessWordRenderer implements WordRenederer {

    private Properties props;

    public HeadlessWordRenderer() {
    }

    public HeadlessWordRenderer(Properties props) {
        this.props = props;
    }

    public BufferedImage renderWord(String word, int width, int height) {
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g2D = image.createGraphics();
        g2D.setColor(Color.black);

        RenderingHints hints = new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

        hints.add(new RenderingHints(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY));

        g2D.setRenderingHints(hints);

        Font[] fonts = Helper.getFonts(props);
        Random generator = new Random();

        char[] wc = word.toCharArray();
        Color fontColor = Helper.getColor(props, Constants.SIMPLE_CAPTCHA_TEXTPRODUCER_FONTC, Color.black);
        g2D.setColor(fontColor);
        FontRenderContext frc = g2D.getFontRenderContext();
        int startPosX = 25;
        for (int i = 0; i < wc.length; i++) {
            char[] itchar = new char[] { wc[i] };
            // g2D.setColor(Color.black);
            int choiceFont = generator.nextInt(fonts.length);
            Font itFont = fonts[choiceFont];
            g2D.setFont(itFont);
            GlyphVector gv = itFont.createGlyphVector(frc, itchar);
            double charWitdth = gv.getVisualBounds().getWidth();

            g2D.drawChars(itchar, 0, itchar.length, startPosX, 35);
            startPosX = startPosX + (int) charWitdth + 2;
            //

        }// for next char array.

        return image;
    }

    public void setProperties(Properties props) {
        this.props = props;
    }

}

И конфигурация этого дела в web.xml выглядит вот так:


...
  <servlet>
    <servlet-name>captcha</servlet-name>
    <servlet-class>nl.captcha.servlet.CaptchaServlet</servlet-class>
    <init-param>
        <param-name>cap.word.imp</param-name>
        <param-value>com.anydoby.commons.web.HeadlessWordRenderer</param-value>
    </init-param>
  </servlet>
...

Вот и все, работающую версию этой самой captcha можно увидеть на моем сайте, например, написав сюда комментарий.

Добавить комментарий

erladoisl
10-10-2018

42

Предыдущая статья Connection refused от MySQL Следующая статья Дубликаты в Hibernate