001/** 002 * Copyright (C) 2006-2025 Talend Inc. - www.talend.com 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.talend.sdk.component.tools; 017 018import java.awt.Color; 019import java.awt.image.BufferedImage; 020import java.io.IOException; 021import java.io.InputStream; 022import java.io.OutputStream; 023import java.nio.file.FileVisitResult; 024import java.nio.file.Files; 025import java.nio.file.Path; 026import java.nio.file.SimpleFileVisitor; 027import java.nio.file.attribute.BasicFileAttributes; 028 029import org.apache.batik.transcoder.TranscoderException; 030import org.apache.batik.transcoder.TranscoderInput; 031import org.apache.batik.transcoder.TranscoderOutput; 032import org.apache.batik.transcoder.image.ImageTranscoder; 033import org.apache.batik.transcoder.image.PNGTranscoder; 034 035public class SVG2Png implements Runnable { 036 037 private final Path iconsFolder; 038 039 private final Log log; 040 041 private final boolean activeWorkarounds; 042 043 public SVG2Png(final Path iconsFolder, final boolean activeWorkarounds, final Object log) { 044 this.iconsFolder = iconsFolder; 045 this.activeWorkarounds = activeWorkarounds; 046 try { 047 this.log = Log.class.isInstance(log) ? Log.class.cast(log) : new ReflectiveLog(log); 048 } catch (final NoSuchMethodException e) { 049 throw new IllegalArgumentException(e); 050 } 051 } 052 053 @Override 054 public void run() { 055 try { 056 Files.walkFileTree(iconsFolder, new SimpleFileVisitor<Path>() { 057 058 @Override 059 public FileVisitResult visitFile(final Path file, final BasicFileAttributes attrs) throws IOException { 060 final String fileName = file.getFileName().toString(); 061 if (fileName.endsWith(".svg")) { 062 final Path svg = file 063 .getParent() 064 .resolve(fileName.substring(0, fileName.length() - ".svg".length()) + "_icon32.png"); 065 if (!Files.exists(svg)) { 066 createPng(file, svg); 067 log.info("Created " + svg); 068 } 069 } 070 return super.visitFile(file, attrs); 071 } 072 }); 073 } catch (final IOException e) { 074 throw new IllegalStateException(e); 075 } 076 } 077 078 private void createPng(final Path svg, final Path png) { 079 final PNGTranscoder transcoder = new PNGTranscoder() { 080 081 @Override 082 public void writeImage(final BufferedImage img, final TranscoderOutput output) throws TranscoderException { 083 if (activeWorkarounds) { 084 ensureAlphaDiff(img); 085 } 086 super.writeImage(img, output); 087 } 088 089 private void ensureAlphaDiff(final BufferedImage img) { 090 // otherwise all web icon are just plain black and studio ignores the alpha in its 091 // md5 cache key so we just get only one icon 092 for (int x = 1; x < img.getWidth() - 1; x++) { 093 for (int y = 1; y < img.getHeight() - 1; y++) { 094 final Color color = new Color(img.getRGB(x, y), true); 095 if (color.getAlpha() == 0) { // enforce some differences for all black images 096 img.setRGB(x, y, new Color(255, 255, 255, color.getAlpha()).getRGB()); 097 } 098 } 099 } 100 } 101 }; 102 transcoder.addTranscodingHint(ImageTranscoder.KEY_HEIGHT, 32f); 103 transcoder.addTranscodingHint(ImageTranscoder.KEY_WIDTH, 32f); 104 try (final InputStream in = Files.newInputStream(svg); final OutputStream out = Files.newOutputStream(png)) { 105 transcoder.transcode(new TranscoderInput(in), new TranscoderOutput(out)); 106 } catch (final IOException | TranscoderException ioe) { 107 throw new IllegalStateException(ioe); 108 } 109 } 110}