首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何使用webdriver (Java)在phantomjs上禁用字体抗锯齿?

如何使用webdriver (Java)在phantomjs上禁用字体抗锯齿?
EN

Stack Overflow用户
提问于 2017-09-02 23:26:21
回答 1查看 593关注 0票数 0

我正在尝试编写检查布局问题的Selenium测试。为此,我在Java端使用Selenium Webdriver,并使用phantomjs作为“浏览器”。我想使用phantomjs,因为它能够制作实际渲染组件的屏幕截图。

默认情况下,phantomjs使用抗锯齿渲染文本,这使得扫描文本变得困难(查找文本基线和执行简单的OCR)。

如何告诉phantomJS不要使用抗锯齿?

EN

回答 1

Stack Overflow用户

发布于 2017-09-02 23:46:13

我使用了下面这个肮脏的技巧在Linux上禁用了phantomjs抗锯齿功能。PhantomJS是使用字体配置构建的,该库在多个位置查找文件"fonts.conf“:请参阅https://www.freedesktop.org/software/fontconfig/fontconfig-user.html

通过创建以下fonts.conf,我们可以禁用字体配置的抗锯齿功能:

代码语言:javascript
复制
<match target="font">
  <edit mode="assign" name="antialias">
    <bool>false</bool>
  </edit>
</match>

其中一个位置由环境变量根据规范定义:$XDG_CONFIG_HOME/fontconfig/fonts.conf。因此,通过创建包含上述内容的临时文件,如/tmp/phantomjs-config/ fontconfig /fonts.conf,然后将XDG_CONFIG_HOME设置为/tmp/phantomjs-config,我们告诉fontconfig读取该文件。

但是有一个问题:默认情况下,PhantomJSDriver类不允许设置环境变量。这是可悲的,因为底层工作者代码PhantomWebDriverService确实允许这样做。

为了解决这个问题,我创建了一个小助手类,在其中我从PhantomJSDriverService复制了一些受保护的方法:

代码语言:javascript
复制
public class MyPhantomDriverService {
    public static PhantomJSDriverService createDefaultService(Capabilities desiredCapabilities, Map<String, String> env) {
        Proxy proxy = null;
        if (desiredCapabilities != null) {
            proxy = Proxy.extractFrom(desiredCapabilities);
        }

        File phantomjsfile = findPhantomJS(desiredCapabilities, "https://github.com/ariya/phantomjs/wiki", "http://phantomjs.org/download.html");
        File ghostDriverfile = findGhostDriver(desiredCapabilities, "https://github.com/detro/ghostdriver/blob/master/README.md", "https://github.com/detro/ghostdriver/downloads");
        Builder builder = new Builder();
        builder.usingPhantomJSExecutable(phantomjsfile)
            .usingGhostDriver(ghostDriverfile)
            .usingAnyFreePort()
            .withProxy(proxy)
            .withLogFile(new File("phantomjsdriver.log"))
            .usingCommandLineArguments(findCLIArgumentsFromCaps(desiredCapabilities, "phantomjs.cli.args"))
            .usingGhostDriverCommandLineArguments(findCLIArgumentsFromCaps(desiredCapabilities, "phantomjs.ghostdriver.cli.args"));
        if(null != env)
            builder.withEnvironment(env);
        return builder.build();
    }

    public static File findPhantomJS(Capabilities desiredCapabilities, String docsLink, String downloadLink) {
        String phantomjspath;
        if (desiredCapabilities != null && desiredCapabilities.getCapability("phantomjs.binary.path") != null) {
            phantomjspath = (String)desiredCapabilities.getCapability("phantomjs.binary.path");
        } else {
            phantomjspath = (new ExecutableFinder()).find("phantomjs");
            phantomjspath = System.getProperty("phantomjs.binary.path", phantomjspath);
        }

        Preconditions.checkState(phantomjspath != null, "The path to the driver executable must be set by the %s capability/system property/PATH variable; for more information, see %s. The latest version can be downloaded from %s", "phantomjs.binary.path", docsLink, downloadLink);
        File phantomjs = new File(phantomjspath);
        checkExecutable(phantomjs);
        return phantomjs;
    }

    protected static File findGhostDriver(Capabilities desiredCapabilities, String docsLink, String downloadLink) {
        String ghostdriverpath;
        if (desiredCapabilities != null && desiredCapabilities.getCapability("phantomjs.ghostdriver.path") != null) {
            ghostdriverpath = (String)desiredCapabilities.getCapability("phantomjs.ghostdriver.path");
        } else {
            ghostdriverpath = System.getProperty("phantomjs.ghostdriver.path");
        }

        if (ghostdriverpath != null) {
            File ghostdriver = new File(ghostdriverpath);
            Preconditions.checkState(ghostdriver.exists(), "The GhostDriver does not exist: %s", ghostdriver.getAbsolutePath());
            Preconditions.checkState(ghostdriver.isFile(), "The GhostDriver is a directory: %s", ghostdriver.getAbsolutePath());
            Preconditions.checkState(ghostdriver.canRead(), "The GhostDriver is not a readable file: %s", ghostdriver.getAbsolutePath());
            return ghostdriver;
        } else {
            return null;
        }
    }

    protected static void checkExecutable(File exe) {
        Preconditions.checkState(exe.exists(), "The driver executable does not exist: %s", exe.getAbsolutePath());
        Preconditions.checkState(!exe.isDirectory(), "The driver executable is a directory: %s", exe.getAbsolutePath());
        Preconditions.checkState(exe.canExecute(), "The driver is not executable: %s", exe.getAbsolutePath());
    }

    private static String[] findCLIArgumentsFromCaps(Capabilities desiredCapabilities, String capabilityName) {
        if (desiredCapabilities != null) {
            Object cap = desiredCapabilities.getCapability(capabilityName);
            if (cap != null) {
                if (cap instanceof String[]) {
                    return (String[])((String[])cap);
                }

                if (cap instanceof Collection) {
                    try {
                        Collection<String> capCollection = (Collection<String>)cap;
                        return (String[])capCollection.toArray(new String[capCollection.size()]);
                    } catch (Exception var4) {
                        System.err.println(String.format("Unable to set Capability '%s' as it was neither a String[] or a Collection<String>", capabilityName));
                    }
                }
            }
        }

        return new String[0];
    }
}

使用这段新代码,我现在可以创建一个PhantomJSDriver,如下所示:

代码语言:javascript
复制
        //-- 1. Make a temp directory which will contain our fonts.conf
        String tmp = System.getProperty("java.io.tmpdir");
        if(tmp == null) {
            tmp = "/tmp";
        }
        File dir = new File(tmp + File.separator + "/_phantomjs-config/fontconfig");
        dir.mkdirs();
        if(! dir.exists()) {
            throw new IOException("Can't create fontconfig directory to override phantomjs font settings at " + dir);
        }

        File conf = new File(dir, "fonts.conf");
        String text = "<match target=\"font\">\n"
            + "<edit mode=\"assign\" name=\"antialias\">\n"
            + "<bool>false</bool>\n"
            + "</edit>\n"
            + "</match>";
        try(FileOutputStream fos = new FileOutputStream(conf)) {
            fos.write(text.getBytes("UTF-8"));
        }

        //-- Set the XDG_CONFIG_HOME envvar; this is used by fontconfig as one of its locations

        Map<String, String> env = new HashMap<>();
        env.put("XDG_CONFIG_HOME", dir.getParentFile().getAbsolutePath());

        PhantomJSDriverService service = MyPhantomDriverService.createDefaultService(capabilities, env);
        wd = new PhantomJSDriver(service, capabilities);

代码的问题

这段代码最重要的问题是,如果有定义抗锯齿的fonts.conf文件(如$HOME/.fonts.conf),它可能会失败。但是对于我的测试用例来说,这是可以工作的。

同样的技巧也适用于无头Chrome ;)

要在无头chrome上禁用抗锯齿功能,请使用上面相同的代码生成fonts.conf文件,然后按如下方式分配Chrome webdriver:

代码语言:javascript
复制
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeDriverService;
import org.openqa.selenium.chrome.ChromeDriverService.Builder;

...

Map<String, String> env = new HashMap<>();
env.put("XDG_CONFIG_HOME", dir.getParentFile().getAbsolutePath());

Builder builder = new Builder();
builder.usingAnyFreePort();
builder.withEnvironment(env);
ChromeDriverService service = builder.build();
return new ChromeDriver(service, dc);
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/46015307

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档