I am creating a program using processing(java) that outputs an SVG file for me to add it to PowerPoint and other programs.
I figured it would be a lot more convenient for the program to directly copy the generated file to my system clipboard, instead of having to copy the file from the output directory.
The trouble is that I can't find a way to set the contents of the clipboard to an SVG file. I've found ways that work with images, but not SVG. To clarify, I want the pasted file to be an SVG too because I want to edit the shapes and lines in PowerPoint afterward.
I am also open to javascript solutions which may work on the web. The goal is to be able to paste an editable collection of shapes, lines, and texts into PowerPoint.
All help is appreciated, thanks in advance!
Edit: Here is the code that works for images:
import java.awt.image.*;
import java.awt.*;
import java.awt.datatransfer.*;
import javax.imageio.*;
void setup() {
size(200, 200);
background(0);
Image img=null;
try {
img = ImageIO.read(new File("path/to/file.jpg"));//path to image file
}
catch (IOException e) {
print(e);
}
ImageSelection imageSelection = new ImageSelection(img);
Toolkit toolkit = Toolkit.getDefaultToolkit();
toolkit.getSystemClipboard().setContents(imageSelection, null);
}
void draw() {
}
public class ImageSelection implements Transferable {
private Image image;
public ImageSelection(Image image) {
this.image = image;//added on
}
public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException {
if (flavor.equals(DataFlavor.imageFlavor) == false) {
throw new UnsupportedFlavorException(flavor);//usually with transferable
}
return image;
}
public boolean isDataFlavorSupported(DataFlavor flavor) {
return flavor.equals(DataFlavor.imageFlavor);//usually with transferable
}
public DataFlavor[] getTransferDataFlavors() {
return new DataFlavor[] {
DataFlavor.imageFlavor//usually with transferable
};
}
}
There is a bit of confusion with the code you posted: so far it looks like for some reason you want to load an image and copy that to the clipboard, not an SVG.
If you want to copy an SVG to the clipboard for PowerPoint there are a few hoops to jump through:
Use the PShapeSVG source code to understand to get the SVG markup
Use the right MIME type: I simply tried this solution
Putting it together:
import processing.svg.*;
import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.SystemFlavorMap;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.Writer;
import java.nio.charset.StandardCharsets;
import org.apache.batik.svggen.SVGGraphics2D;
import org.apache.batik.svggen.SVGGraphics2DIOException;
void setup(){
PGraphicsSVG svg = (PGraphicsSVG)createGraphics(300,300,SVG);
svg.beginDraw();
svg.background(#4db748);
svg.noFill();
svg.strokeWeight(27);
int a = 80;
int b = 220;
svg.line(a,a,b,b);
svg.line(a,b,b,a);
svg.line(a,a,b,a);
svg.line(a,b,b,b);
svg.ellipse(150, 150, 250, 250);
copyToClipboard(svg);
// normally you would call endDraw, but this will obviously throw an error if you didn't specify a filename in createGraphics()
//svg.endDraw();
println("svg copied to clipboard");
exit();
}
String getSVGString(PGraphicsSVG svg){
// make a binary output stream
ByteArrayOutputStream output = new ByteArrayOutputStream();
// make a writer for it
Writer writer = PApplet.createWriter(output);
// same way the library writes to disk we write to the byte array stream
try{
((SVGGraphics2D) svg.g2).stream(writer, false);
} catch (SVGGraphics2DIOException e) {
e.printStackTrace();
}
// convert bytes to an UTF-8 encoded string
return new String( output.toByteArray(), StandardCharsets.UTF_8 );
}
void copyToClipboard(PGraphicsSVG svg){
// get the SVG markup as a string
String svgString = getSVGString(svg);
println(svgString);
// access the system clipboard
Clipboard clip = Toolkit.getDefaultToolkit().getSystemClipboard();
// get an binary clipboard with the correct SVG MIME type
SvgClip strSVG = new SvgClip(svgString);
// commit the clipboard encoded SVG to clipboard
clip.setContents(strSVG, null);
}
// blatant copy/adapation of https://stackoverflow.com/questions/33726321/how-to-transfer-svg-image-to-other-programs-with-dragndrop-in-java
class SvgClip implements Transferable{
String svgString;
DataFlavor svgFlavor = new DataFlavor("image/svg+xml; class=java.io.InputStream","Scalable Vector Graphic");
DataFlavor [] supportedFlavors = {svgFlavor};
SvgClip(String svgString){
this.svgString = svgString;
SystemFlavorMap systemFlavorMap = (SystemFlavorMap) SystemFlavorMap.getDefaultFlavorMap();
systemFlavorMap.addUnencodedNativeForFlavor(svgFlavor, "image/svg+xml");
}
#Override public DataFlavor[] getTransferDataFlavors(){
return this.supportedFlavors;
}
#Override public boolean isDataFlavorSupported(DataFlavor flavor){
return true;
}
#Override public Object getTransferData(DataFlavor flavor)
throws UnsupportedFlavorException, IOException{
return new ByteArrayInputStream(svgString.getBytes(StandardCharsets.UTF_8));
}
}
Note Call copyToClipboard(svg) after your last drawing command, but before PGraphicsSVG's endDraw() call (otherwise it will return an empty SVG document)
The result in PowerPoint:
Related
I want to make a discord bot, that when the user types -m skelt a picture will be shown from the bot. Here is what I got so far: Can somone please help me. Thanks!
package lairex59.Commands;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import lairex59.Main;
import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.events.message.guild.GuildMessageReceivedEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
public class Comment extends ListenerAdapter
{
public void onGuildMessageReceived(GuildMessageReceivedEvent event){
String[] args = event.getMessage().getContentRaw().split("\\s+");
if (args[0].equalsIgnoreCase(Main.prefix + "help")) {
EmbedBuilder info = new EmbedBuilder();
info.setTitle(":among_us_lime:Among Us help cnter");
info.setDescription("Among Us code center :office:");
info.setColor(0xf45642);
info.setFooter("Created by Laraib", event.getMember().getUser().getAvatarUrl());
event.getChannel().sendTyping().queue();
event.getChannel().sendMessage(info.build()).queue();
info.clear();
}
if ((args[0].equalsIgnoreCase(Main.prefix + "m")) && (args[1].equalsIgnoreCase("polus"))) {
event.getChannel().sendTyping().queue();
event.getChannel().sendMessage("Polus file").queue();
}
if (args[0].equalsIgnoreCase(Main.prefix + "m") && (args[1].equalsIgnoreCase("mira"))) {
event.getChannel().sendTyping().queue();
event.getChannel().sendMessage("Mira file").queue();
}
if (args[0].equalsIgnoreCase(Main.prefix + "m") && (args[1].equalsIgnoreCase("skelt"))) {
event.getChannel().sendTyping().queue();
BufferedImage image = null;
File f = null;
try {
f = new File ("D:\\Laraib\\Images\\Skelt.jpg");
image = ImageIO.read(f);
}
catch(IOException e) {
System.out.println("Error"+e);
}
try {
f = new File ("D:\\Laraib\\Images\\Skelt.jpg");
ImageIO.write(image, "jpg", f);
}
catch (IOException e) {
System.out.println("Error"+e);
}
}
}
}
I managed to read the file but don't know how i can tell the bot to send an image. Every help is needed. Thanks!
Discord does not ask to specify if the file sent is an image or something else, it just sends the file, it is the client who, from the file extension, will display the image as an image, so your BufferedImage is useless.
So, to send your image, it's just plain silly:
The MessageAction interface you have a method MessageAction#addFile(File)
All you have to do is to call this method, and to send all this to the wrong person (like the queue method for example).
File file = new File("path");
if (Objects.nonNull(file)) {
event.getChannel().sendMessage("Here is my image !").addFile(file).queue();
} else {
event.getChannel().sendMessage("Sorry, I can't found the image :c").queue();
}
Here's the java doc : https://ci.dv8tion.net/job/JDA/javadoc/net/dv8tion/jda/api/requests/restaction/MessageAction.html
EDIT:
Or, as #minn reminded me, you don't have to add the file in the MessageAction but you can directly send the file without additional content with the method MessageChannel#sendFile(file).
Here's the doc: https://ci.dv8tion.net/job/JDA/javadoc/net/dv8tion/jda/api/entities/MessageChannel.html
I want to create a Java class that I use to export images. This class will be exported in .JAR file which will allow me to integrate it directly into another project by passing as input parameter the name of the file and in return I would have this image in PNG format.
That's what I tried:
package militarySymbolsLibrary;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
public class MainEntry {
public static void main(String agrs[]) {
}
public static BufferedImage generateImage(String symbolCode) {
File imageFile = new File("/pictures/SSGPU-------.png");
BufferedImage image;
try {
image = ImageIO.read(imageFile);
} catch (IOException e) {
image = null;
e.printStackTrace();
}
return image;
}
}
Pictures are stocked in folder pictures like this treeview below:
src
MainEntry.java
pictures
SSGPU-------.png
Then I export this class in .JAR file, I add it to my other program, I pass a parameter (picture's name except for this test) and normally my class return PNG file. But I have an error telling me that the file path is not the rigth one.
How can I solve this problem?
Thank you
When loading a font with a fontLoader class I made (code below) I get an error: java.io.IOException: Problem reading font data.
This is for a 2D game I am developing. I've tried other ways of loading in the font but nothings worked.
This is my Font class with a loadFont method.
package dev.java2dgame.gfx;
import java.awt.Font;
import java.awt.FontFormatException;
import java.io.IOException;
import java.io.File;
public class Fonts {
public static Font loadFont(String path, float size){
try {
return Font.createFont(Font.TRUETYPE_FONT, Font.class.getClass().getResourceAsStream(path)).deriveFont(Font.PLAIN, size);
} catch (FontFormatException | IOException e) {
e.printStackTrace();
System.exit(1);
}
return null;
}
}
This is where I am calling the loadFont() method and the path I am typing in. It is in my Assets class that loads and holds all my game assets. I know the path to the font file is correct because I made sure and can load other images and things from the fonts folder as a test. I also checked 10 times over to make sure I wrote the right name.
public class Assets {
public static final int width = 64, height = 64;
public static BufferedImage nothing, floor, aud_floor, gym_floor,
front_wall, left_wall, right_wall, shelf_wall, whiteboard_wall, closed_window,
storm_window, bookshelf1, bookshelf2;
public static Font font36;
public static BufferedImage saw;
public static SpriteSheet tileSheet;
public static void init() {
font36 = Fonts.loadFont("/fonts/munro.ttf", 16);
tileSheet = new SpriteSheet("/sprites/tilesheet.png");
saw = ImageLoader.loadImage("/sprites/singlesprites/woodshop_saw.png");
nothing = tileSheet.crop(width, height, width, height);
The rest of this class is cut off because the info in it is not needed.
And this is the error I get when I run the code.
java.io.IOException: Problem reading font data.
at java.desktop/java.awt.Font.createFont0(Font.java:1183)
at java.desktop/java.awt.Font.createFont(Font.java:1052)
at dev.java2dgame.gfx.Fonts.loadFont(Fonts.java:12)
at dev.java2dgame.gfx.Assets.init(Assets.java:21)
at dev.java2dgame.main.Game.init(Game.java:54)
at dev.java2dgame.main.Game.run(Game.java:93)
at java.base/java.lang.Thread.run(Thread.java:835)
I was able to fix the problem using this code!
public static Font loadFont(String path, float size){
try {
InputStream fileStream = Fonts.class.getResourceAsStream(path);
Font myFont = Font.createFont(Font.TRUETYPE_FONT, fileStream);
return myFont.deriveFont(Font.PLAIN, size);
} catch (FontFormatException | IOException e) {
e.printStackTrace();
System.exit(1);
}
return null;
}
This code attempts to resize images in a directory called "imgs". Unfortunately for some reason when I uncomment the listFiles(..) loop ImageIO.read(sourceImageFile) will return null. Yet processing the same file straightaway outside the loop (res("imgs/foto_3.jpg")) works. So apparently, this loop is preventing the files from being read. Solutions?
import java.awt.image.*;
import java.io.*;
import javax.imageio.*;
import static org.imgscalr.Scalr.*;
public class App {
public static void main(String[] args) throws IOException {
// for (File sourceImageFile : new File("imgs").listFiles()) {
// res("imgs/"+sourceImageFile.getName());
// }
res("imgs/foto_3.jpg");
}
public static void res(String arg) throws IOException {
File sourceImageFile = new File(arg);
BufferedImage img = ImageIO.read(sourceImageFile);
BufferedImage thumbnail = resize(img, 500);
thumbnail.createGraphics().drawImage(thumbnail, 0, 0, null);
ImageIO.write(thumbnail, "jpg", new File("resized/" + sourceImageFile.getName()));
}
}
To reproduce the problem you can download the Maven project.
Can you change res to accept a File object rather than a String? Then you could write the following, which is a lot nicer:
for (File sourceImageFile : new File("imgs").listFiles()) {
res(sourceImageFile);
}
As to your original question, try adding some tracing statements or using a debugger to find what exactly gets passed to res.
I am not sure why the file listing iteration would mess with the thumbnail generation, but you mentioned privately to me that you were using imgscalr and were curious what the correct code to batch-process a directory would look like, so I wrote up this example code for you.
The code below will process any directory (imgs is hard-coded to stay consistent with your example code) and write it out to any other directory (resized is used to stay consistent -- feel free to change either directory)
import static org.imgscalr.Scalr.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
public class ScaleDirExample {
public static void main(String[] args) throws IOException {
File[] images = new File("imgs").listFiles();
for (File f : images) {
System.out.println("Processing: " + f.getName() + "...");
if (f.isDirectory()) {
System.out.println("\tSkipping, file is a directory...");
continue;
} else
process(f);
}
}
private static void process(File file) throws IOException {
// Load image.
BufferedImage image = ImageIO.read(file);
// Resize image.
image = resize(image, 500);
// Save the resized image as the thumbnail.
saveThumbnail(file, image);
}
private static void saveThumbnail(File originalFile, BufferedImage thumbnail)
throws IOException {
String filename = originalFile.getName();
// Determine file extension.
String fileExt = filename.substring(filename.lastIndexOf('.') + 1);
// Save the thumbnail to the resized dir.
ImageIO.write(thumbnail, fileExt, new File("resized/" + filename));
}
}
The call to resize(image, 500) can be modified to match any of the Scalr.resize methods - you can pass filters or improve quality if you want.
Example output from my test setup looks like:
Processing: flower-dog-gimp.jpg...
Processing: flower-dog.jpg...
Processing: logoOXdaComida.png...
Processing: mr-t-thumbnail.jpg...
Processing: mr-t.jpg...
Processing: problem-trans-peter-griffin.png...
Hope that helps!
OK, I figured it out. now it's working.
You (or whoever created the downloadable project u pasted here) are using Mac OS, and it automatically creates a .DS_Store file.
When you try to pass it to the res method, it doesn't know how to handle a non-image file and acts as null.
public static void main(String[] args) throws IOException {
for (File sourceImageFile : new File("imgs").listFiles()) {
if (sourceImageFile.getName().endsWith(".jpg"))
res(sourceImageFile.getAbsolutePath());
}
}
This is the modified void main method. it works, u can refine the if statement for more in depth filtering of wrong files.
Also I changed the argument given to the res method. it looks better now, as getAbsoulutePath returns the name and the path.
Let me know how it worked
One obvious way to debug this to output the specific sourceImageFile that ImageIO.read(..) is returning null on. I suspect its because listFiles will give you a list of all files and directories that are in the image directory. listFiles javadoc. You can prevent that by using a FileFilter that makes sure that listFiles only returns files and additionally files of the right type.
An example of a file filter that only returns file is below:
import java.io.FileFilter
class RegularFilesOnlyFileFilter implements FileFilter {
public boolean accept(File pathName) {
return pathName.isFile();
}
}
The way to use this filter is this - new File("imgs").listFiles(new RegularFilesOnlyFilesFilter())
I've changed res method:
public static void res(File arg) throws IOException {
if (arg.contains(".DS_Store")) {
return;
}
A mac-issue (or should filter non-image files, as was suggested)!
I often have to add my signature to a document. The document can be of different kinds.
My signature is stored as an image in signature.jpg.
I would like to write a Java program that automatically places this image in the clipboard, so that I only have to paste it into the document.
You have to use me method: setContents from the Clipboard class.
Modified from:
http://www.exampledepot.com/egs/java.awt.datatransfer/ToClipImg.html
import java.awt.*;
import java.awt.datatransfer.*;
public class LoadToClipboard {
public static void main( String [] args ) {
Toolkit tolkit = Toolkit.getDefaultToolkit();
Clipboard clip = tolkit.getSystemClipboard();
clip.setContents( new ImageSelection( tolkit.getImage("StackOverflowLogo.png")) , null );
}
}
class ImageSelection implements Transferable {
private Image image;
public ImageSelection(Image image) {
this.image = image;
}
// Returns supported flavors
public DataFlavor[] getTransferDataFlavors() {
return new DataFlavor[]{DataFlavor.imageFlavor};
}
// Returns true if flavor is supported
public boolean isDataFlavorSupported(DataFlavor flavor) {
return DataFlavor.imageFlavor.equals(flavor);
}
// Returns image
public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException {
if (!DataFlavor.imageFlavor.equals(flavor)) {
throw new UnsupportedFlavorException(flavor);
}
return image;
}
}
Take a look at the java.awt.datatransfer.* classes. You'll essentially have to develop an implementation of the java.awt.datatransfer.Transferable interface that will transfer an image to the clipboard.
Edit: Found a couple of tutorials that might help:
Java Tip #61
Use Java to Interact with Your Clipboard (see page 6 of the tutorial)