Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 72 additions & 24 deletions html2image/pom.xml
Original file line number Diff line number Diff line change
@@ -1,63 +1,111 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

<modelVersion>4.0.0</modelVersion>

<groupId>gui.ava</groupId>
<artifactId>html2image</artifactId>
<packaging>jar</packaging>
<version>2.0-SNAPSHOT</version>
<version>3.0.0-SNAPSHOT</version>
<name>html2image</name>
<url>http://maven.apache.org</url>
<url>https://maven.apache.org</url>

<!-- Java 17 LTS -->
<properties>
<java.version>17</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.release>${java.version}</maven.compiler.release>
<maven.compiler.target>${java.version}</maven.compiler.target>
<maven.compiler.source>${java.version}</maven.compiler.source>

<flying-saucer.version>9.9.1</flying-saucer.version>
</properties>

<!-- Dependencies -->
<dependencies>
<dependency>
<groupId>org.xhtmlrenderer</groupId>
<artifactId>core-renderer</artifactId>
<version>R8</version>
</dependency>

<!-- ==== PARSING ====================================== -->

<!-- NekoHtml 1.9.x -->
<dependency>
<groupId>net.sourceforge.nekohtml</groupId>
<artifactId>nekohtml</artifactId>
<version>1.9.14</version>
<version>1.9.22</version>
</dependency>

<!-- Neko HtmlUnit version without Xerces is very limited! -->
<!-- <dependency>-->
<!-- <groupId>org.htmlunit</groupId>-->
<!-- <artifactId>neko-htmlunit</artifactId>-->
<!-- <version>4.4.0</version>-->
<!-- </dependency>-->

<!-- Also the official HtmlUnit 4.x is very limited! -->
<!-- <dependency>-->
<!-- <groupId>org.htmlunit</groupId>-->
<!-- <artifactId>htmlunit</artifactId>-->
<!-- <version>4.4.0</version>-->
<!-- </dependency>-->

<!-- ==== RENDERING ================================================== -->

<dependency>
<groupId>org.xhtmlrenderer</groupId>
<artifactId>flying-saucer-core</artifactId>
<version>${flying-saucer.version}</version>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.5</version>
<groupId>org.xhtmlrenderer</groupId>
<artifactId>flying-saucer-pdf</artifactId>
<version>${flying-saucer.version}</version>
</dependency>

<!-- ==== UTILS ====================================================== -->

<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.8.1</version>
<scope>test</scope>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.16.0</version>
</dependency>

<!-- ==== TEST ======================================================== -->

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>3.0.3.RELEASE</version>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.11.0</version>
<scope>test</scope>
</dependency>

</dependencies>

<!-- DISTRIBUTION -->
<distributionManagement>
<repository>
<id>jfrog-third-party-releases-local</id>
<!--<url>http://yoava.artifactoryonline.com/yoava/libs-releases-local</url>-->
<!--<url>http://yoava.artifactoryonline.com/yoava/libs-snapshots-local</url>-->
<url>http://repo.jfrog.org/artifactory/third-party-releases-local</url>
<url>https://repo.jfrog.org/artifactory/third-party-releases-local</url>
</repository>
</distributionManagement>

<!-- BUILD
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.13.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>utf-8</encoding>
<source>${java.version}</source>
<target>${java.version}</target>
<encoding>${project.build.sourceEncoding}</encoding>
</configuration>
</plugin>
</plugins>
</build>
-->

</project>
20 changes: 12 additions & 8 deletions html2image/src/main/java/gui/ava/html/Html2Image.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
package gui.ava.html;

import java.io.File;
import java.io.InputStream;
import java.io.Reader;
import java.net.URI;
import java.net.URL;

import org.w3c.dom.Document;

import gui.ava.html.imagemap.HtmlImageMap;
import gui.ava.html.imagemap.HtmlImageMapImpl;
import gui.ava.html.parser.HtmlParser;
Expand All @@ -8,19 +16,14 @@
import gui.ava.html.pdf.PdfRendererImpl;
import gui.ava.html.renderer.ImageRenderer;
import gui.ava.html.renderer.ImageRendererImpl;
import org.w3c.dom.Document;

import java.io.File;
import java.io.InputStream;
import java.io.Reader;
import java.net.URI;
import java.net.URL;

/**
* @author Yoav Aharoni
*/
public class Html2Image {
private HtmlParser parser = new HtmlParserImpl();

private final HtmlParser parser = new HtmlParserImpl();

private HtmlImageMap htmlImageMap;
private ImageRenderer imageRenderer;
private PdfRenderer pdfRenderer;
Expand Down Expand Up @@ -91,4 +94,5 @@ public static Html2Image fromInputStream(InputStream inputStream) {
html2Image.getParser().load(inputStream);
return html2Image;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
* @author Yoav Aharoni
*/
public class RenderException extends RuntimeException {

public RenderException(String message, Throwable cause) {
super(message, cause);
}

}
83 changes: 41 additions & 42 deletions html2image/src/main/java/gui/ava/html/image/HtmlImageGenerator.java
Original file line number Diff line number Diff line change
@@ -1,29 +1,29 @@
package gui.ava.html.image;

import gui.ava.html.image.util.FormatNameUtil;
import gui.ava.html.image.util.SynchronousHTMLEditorKit;
import gui.ava.html.link.LinkInfo;

import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.net.URL;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

import javax.imageio.ImageIO;
import javax.swing.*;

import gui.ava.html.link.LinkInfo;
import gui.ava.html.util.FormatNameUtil;

/**
* @author Yoav Aharoni
*/
public class HtmlImageGenerator {
private JEditorPane editorPane;
static final Dimension DEFAULT_SIZE = new Dimension(800, 800);

private static final Dimension DEFAULT_SIZE = new Dimension(800, 800);

private final JEditorPane editorPane;

public HtmlImageGenerator() {
editorPane = createJEditorPane();
Expand Down Expand Up @@ -63,24 +63,24 @@ public void loadUrl(String url) {

public void loadHtml(String html) {
editorPane.setEditable(false);
editorPane.setText(html);
editorPane.setContentType("text/html");
editorPane.setText(html);
onDocumentLoad();
}

public String getLinksMapMarkup(String mapName) {
final StringBuilder markup = new StringBuilder();
markup.append("<map name=\"").append(mapName).append("\">\n");
for (LinkInfo link : getLinks()) {
final List<Rectangle> bounds = link.getBounds();
for (Rectangle bound : bounds) {
final List<Rectangle2D> bounds = link.getBounds();
for (Rectangle2D bound : bounds) {
final int x1 = (int) bound.getX();
final int y1 = (int) bound.getY();
final int x2 = (int) (x1 + bound.getWidth());
final int y2 = (int) (y1 + bound.getHeight());
markup.append(String.format("<area href=\"%s\" coords=\"%s,%s,%s,%s\" shape=\"rect\"", link.getHref(), x1, y1, x2, y2));
final String title = link.getTitle();
if (title != null && !title.equals("")) {
if (title != null && !title.isEmpty()) {
markup.append(" title=\"").append(title.replace("\"", "&quot;")).append("\"");
}
markup.append(">\n");
Expand All @@ -101,9 +101,7 @@ public void saveAsHtmlWithMap(String file, String imageUrl) {
}

public void saveAsHtmlWithMap(File file, String imageUrl) {
FileWriter writer = null;
try {
writer = new FileWriter(file);
try (FileWriter writer = new FileWriter(file)) {
writer.append("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n");
writer.append("<html>\n<head></head>\n");
writer.append("<body style=\"margin: 0; padding: 0; text-align: center;\">\n");
Expand All @@ -115,15 +113,7 @@ public void saveAsHtmlWithMap(File file, String imageUrl) {
writer.append("</body>\n</html>");
} catch (IOException e) {
throw new RuntimeException(String.format("Exception while saving '%s' html file", file), e);
} finally {
if (writer != null) {
try {
writer.close();
} catch (IOException ignore) {
}
}
}

}

public void saveAsImage(String file) {
Expand All @@ -146,8 +136,7 @@ public void saveAsImage(File file) {
}
}

protected void onDocumentLoad() {
}
protected void onDocumentLoad() {}

public Dimension getDefaultSize() {
return DEFAULT_SIZE;
Expand Down Expand Up @@ -179,25 +168,35 @@ protected JEditorPane createJEditorPane() {
final SynchronousHTMLEditorKit kit = new SynchronousHTMLEditorKit();
editorPane.setEditorKitForContentType("text/html", kit);
editorPane.setContentType("text/html");
editorPane.addPropertyChangeListener(new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
if (evt.getPropertyName().equals("page")) {
onDocumentLoad();
}
editorPane.addPropertyChangeListener(event -> {
if (event.getPropertyName().equals("page")) {
onDocumentLoad();
}
});
return editorPane;
}

public void show() {
JFrame.setDefaultLookAndFeelDecorated(true);
JFrame frame = new JFrame();
frame.setTitle("My First Swing Application");
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
JLabel label = new JLabel("Welcome");
frame.add(label);
frame.add(editorPane);
frame.pack();
frame.setVisible(true);
// the main window
final JFrame view = new JFrame();

// create the view
view.setTitle("HtmlImageGenerator");
view.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JLabel label = new JLabel("Label");
view.add(label);
view.add(editorPane);
view.pack();

// set the system look & feel
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
SwingUtilities.updateComponentTreeUI(view);
} catch (Exception ignored) {}

// show the view
view.setLocationByPlatform(true);
view.setVisible(true);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package gui.ava.html.image;

import javax.swing.text.Document;
import javax.swing.text.Element;
import javax.swing.text.View;
import javax.swing.text.ViewFactory;
import javax.swing.text.html.HTMLDocument;
import javax.swing.text.html.HTMLEditorKit;
import javax.swing.text.html.ImageView;

/**
* @author Yoav Aharoni
*/
public class SynchronousHTMLEditorKit extends HTMLEditorKit {

@Override
public Document createDefaultDocument() {
HTMLDocument doc = (HTMLDocument) super.createDefaultDocument();
doc.setAsynchronousLoadPriority(-1);
return doc;
}

@Override
public ViewFactory getViewFactory() {
return new HTMLFactory() {
@Override
public View create(Element elem) {
View view = super.create(elem);
if (view instanceof ImageView imageView) {
imageView.setLoadsSynchronously(true);
}
return view;
}
};
}

}
Loading