Skip to content

Commit

Permalink
Add a new batch of SVG icons, and more mappings from old PNG/GIF file…
Browse files Browse the repository at this point in the history
…s to artboard names and SVG files.

Reorder some of the mappings to keep similar-looking icons together in the generated icons.html file.

Icon script improvements:
* Allow SVG paths to be included in mappings.tsv, for new icons that do not have a corresponding PNG or GIF file. (Did not end up using this feature currently. But it might be useful in the future.)
* Permit a subset of SVG files to be copied into the NetBeans repo, depending on what files exist in the illustrator_exports folder.
* Add an explanatory preamble to the generated icons.html file, with links to the README and other relevant information.
* In the generated icons.html, sort unassigned bitmap icons by first path observed. (Help keeps related icons together.)

This commit corresponds to the changes in apache/netbeans#8083, including the final PR revisions.
  • Loading branch information
eirikbakke committed Jan 5, 2025
1 parent 762966c commit 3c9eb9a
Show file tree
Hide file tree
Showing 9 changed files with 9,736 additions and 7,400 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,4 @@
/jsstub-generator/node_modules/
/jsstub-generator/nbproject/
/jsstub-generator/out.old/
.DS_Store
1 change: 1 addition & 0 deletions icon-scripts/.gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
/hidpi-icons/target/
/illustrator_exports/
4 changes: 4 additions & 0 deletions icon-scripts/README.txt
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,10 @@ The IconTasks script reads the following files as input:
icons. IconTasks will also reorder rows to keep mappings for each
artboard together, and to list ready artboards first.

In some cases, a new SVG icon may not have a corresponding PNG or GIF
icon. In this case the path to the SVG file can be used directly in
mappings.tsv.

* icon-scripts/tables/illustrator_exports/icon_*.svg
If there are SVG files in the illustrator_exports folder, they are assumed
to have been exported from Illustrator and will be copied into appropriate
Expand Down
5 changes: 5 additions & 0 deletions icon-scripts/hidpi-icons/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@
<artifactId>guava</artifactId>
<version>33.0.0-jre</version>
</dependency>
<dependency>
<groupId>com.github.weisj</groupId>
<artifactId>jsvg</artifactId>
<version>1.6.1</version>
</dependency>
</dependencies>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@
*/
package org.netbeans.build.icons;

import com.github.weisj.jsvg.SVGDocument;
import com.github.weisj.jsvg.geometry.size.FloatSize;
import com.github.weisj.jsvg.parser.LoaderContext;
import com.github.weisj.jsvg.parser.SVGLoader;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
Expand All @@ -29,9 +33,11 @@
import com.google.common.collect.Sets;
import java.awt.Dimension;
import java.awt.image.BufferedImage;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
Expand All @@ -58,6 +64,7 @@
*/
public class IconTasks {
private static final String LICENSE_HEADER = readLicenseHeader();
private static final SVGLoader SVG_LOADER = new SVGLoader();

public static void main(String[] args) throws IOException {
final File ICON_SCRIPTS_DIR = new File(System.getProperty("user.dir"), "../");
Expand Down Expand Up @@ -127,7 +134,7 @@ public static void main(String[] args) throws IOException {
for (ArtboardName artboard : readyArtboards) {
File artboardSVGFile = getIllustratorSVGFile(ILLUSTRATOR_SVGS_DIR, artboard);
if (!artboardSVGFile.exists()) {
throw new RuntimeException("File not found: " + artboardSVGFile);
System.out.println("Illustrator export " + artboardSVGFile + " not found; skipping.");
}
}
}
Expand All @@ -139,7 +146,9 @@ public static void main(String[] args) throws IOException {
for (Entry<ArtboardName, Hash> entry : hashesByArtboard.entries()) {
ArtboardName artboard = entry.getKey();
Hash hash = entry.getValue();
for (IconPath ip : filesByHash.get(hash)) {
List<IconPath> pathsForThisHash = Lists.newArrayList(filesByHash.get(hash));
pathsForThisHash.sort((e1, e2) -> e1.toString().compareTo(e2.toString()));
for (IconPath ip : pathsForThisHash) {
Util.putChecked(newArtboardByFile, ip, artboard);
}
}
Expand All @@ -155,12 +164,16 @@ public static void main(String[] args) throws IOException {
unassignedIcons.add(new SimpleEntry(ip, dim));
}
}
// Order unassigned icons by width, then by height.
/* Order unassigned icons by width, then by height, then by path. (If there are multiple
paths, the first path will end up being used for sorting per putIfAbsent below.) */
unassignedIcons.sort((e1, e2) -> {
int ret = Integer.compare(e1.getValue().width, e2.getValue().width);
if (ret == 0) {
ret = Integer.compare(e1.getValue().height, e2.getValue().height);
}
if (ret == 0) {
ret = e1.getKey().toString().compareTo(e2.getKey().toString());
}
return ret;
});
for (Entry<IconPath,Dimension> entry : unassignedIcons) {
Expand All @@ -175,7 +188,6 @@ public static void main(String[] args) throws IOException {
for (ArtboardName artboard : readyArtboards) {
final String svgContentToWrite;
if (copySVGfiles) {
// Existence was checked earlier.
svgContentToWrite = prepareSVGWithInsertedLicense(ILLUSTRATOR_SVGS_DIR, artboard);
} else {
svgContentToWrite = null;
Expand Down Expand Up @@ -208,22 +220,41 @@ public static void main(String[] args) throws IOException {
PrintWriter htmlPW = createPrintWriter(ICONS_HTML_FILE))
{
htmlPW.println(LICENSE_HEADER);
htmlPW.println("<html>\n" +
"<head>\n" +
"<title>Icons</title>\n" +
// "<base href='../../'>\n" +
"<style>\n" +
"table td, table td * { vertical-align: top; margin-left: 5px; }\n" +
"thead td { padding-right: 10px; padding-bottom: 10px; }\n" +
"td { padding-right: 10px; }\n" +
"thead { font-weight: bold; }\n" +
"</style>" +
"</head>" +
"<body>");
htmlPW.println("<h1>NetBeans Bitmap and SVG Icons</h1>\n" +
"<table border='0' cellpadding='1' cellspacing='0'>\n" +
"<thead><tr><td>Artboard Name<td>SVG<td>Bitmap<td>Dim<td>" +
"Path of Bitmap in Source Repo (no icon image means same as previous)</tr></thead>");
htmlPW.println("""
<html>
<head>
<title>NetBeans Icons</title>
<!--The the image paths in this file assume that this HTML file is located in the
root of a clone of the NetBeans source repository. To use images from a specific
GitHub branch (e.g. belonging to a pull request), a line like the following can
be included here:
<base href="https://raw.githubusercontent.com/eirikbakke/incubator-netbeans/pr-svgs240612/">
-->
<style>
table td, table td * { vertical-align: top; margin-left: 5px; }
thead td { padding-right: 10px; padding-bottom: 10px; }
td { padding-right: 10px; }
thead { font-weight: bold; }
</style></head><body>
<h1>NetBeans Bitmap and SVG Icons</h1>
<p>This file lists bitmap icon files (GIF and PNG) in the NetBeans repo along with
their mapping to corresponding modernized SVG versions where available. A single
"artboard name" is assigned to icons that are exact or near duplicates, or which
are intended to have the same meaning.
<p>This file is generated by the
<tt>icon-scripts/hidpi-icons</tt> script in the
<a href="https://github.com/apache/netbeans-tools">netbeans-tools</a>
repository. Image paths are relative to the root of the NetBeans
<a href="https://github.com/apache/netbeans">source repository</a>.
<p>See the <a href="https://github.com/apache/netbeans-tools/tree/master/icon-scripts#readme">README</a>,
<a href="https://cwiki.apache.org/confluence/display/NETBEANS/SVG+Icon+Style+Guide+and+Process">Style Guide</a>, and
<a href="https://vimeo.com/667860571">Icon Drawing Video Tutorial</a> for more information.
"""
);
htmlPW.println("""
<p><table border='0' cellpadding='1' cellspacing='0'>
<thead><tr><td>Artboard Name<td>SVG<td>Bitmap<td>Dim<td>Path of Bitmap in
Source Repo (no icon image means same as for previous row)</tr></thead>""");
int artboardIdx = 0;
Set<ArtboardName> artboardsInOrder = Sets.newLinkedHashSet();
artboardsInOrder.addAll(Sets.filter(filesByArtboard.keySet(), a -> readyArtboards.contains(a)));
Expand All @@ -245,7 +276,7 @@ public static void main(String[] args) throws IOException {
for (IconPath ip : ips) {
Hash hash = Util.getChecked(iconHashesByFile, ip);
if (!UNASSIGNED_ARTBOARD.equals(artboard)) {
mappingsPW.println(artboard + "\t" + ip);
mappingsPW.println(artboard + " " + ip);
}

htmlPW.print(artboardIdx % 2 == 0 ? "<tr>" :
Expand Down Expand Up @@ -327,9 +358,6 @@ private static ImmutableMap<IconPath, ArtboardName> readArtboardByFileMappings(F
if (parts.length == 2) {
String artboard = parts[0].trim();
String filePath = parts[1].trim();
if (filePath.endsWith(".svg")) {
throw new RuntimeException("File mapping cannot be to an SVG file.");
}
File actualFile = new File(nbsrcDir, filePath);
if (!actualFile.exists()) {
throw new RuntimeException("File does not exist: " + actualFile);
Expand Down Expand Up @@ -390,6 +418,9 @@ private static ImmutableSet<ArtboardName> readReadyArtboards(File file) throws I
private static String prepareSVGWithInsertedLicense(File illustratorSVGsDir, ArtboardName artboard) throws IOException {
StringBuilder ret = new StringBuilder();
File srcFile = getIllustratorSVGFile(illustratorSVGsDir, artboard);
if (!srcFile.exists()) {
return null;
}
try (BufferedReader br = new BufferedReader(new FileReader(srcFile))) {
String line;
boolean firstLine = true;
Expand Down Expand Up @@ -426,6 +457,17 @@ private static String readLicenseHeader() {
}

private static @Nullable Dimension readImageDimension(File file) throws IOException {
if (file.getName().endsWith(".svg")) {
SVGDocument svgDocument = SVG_LOADER.load(new BufferedInputStream(
new FileInputStream(file)), null, LoaderContext.builder().build());
if (svgDocument == null) {
throw new IOException("Failed to load SVG file " + file);
}
FloatSize floatSize = svgDocument.size();
return new Dimension(
(int) Math.ceil(floatSize.getWidth()),
(int) Math.ceil(floatSize.getHeight()));
}
BufferedImage image = ImageIO.read(file);
if (image == null)
throw new IOException("ImageIO.read returned null for " + file);
Expand Down
14,550 changes: 8,210 additions & 6,340 deletions icon-scripts/nb_vector_icons.ai

Large diffs are not rendered by default.

Loading

0 comments on commit 3c9eb9a

Please sign in to comment.