Load SVG file in javafx 2.0 - java

I'd like to display a svg image in javafx 2.0, but I don't find such a thing in the API. I guess it's because it's still in beta.
Until the final release, how can I load a svg ? Is there already a library which can handle that, or do I need to parse myself the file and then create the corresponding shapes ?
Thanks

Based on the answer of this question I found a working solution.
1. Include references to the Batik SVG Toolkit jars
2. Implement your own Transcoder
(based on this answer by Devon_C_Miller)
class MyTranscoder extends ImageTranscoder {
private BufferedImage image = null;
#Override
public BufferedImage createImage(int w, int h) {
image = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
return image;
}
#Override
public void writeImage(BufferedImage img, TranscoderOutput out) {
}
public BufferedImage getImage() {
return image;
}
}
3. Get a BufferedImage from your svg
(based on hint in this answer by John Doppelmann)
String uri = "path_to_svg/some.svg";
MyTranscoder transcoder = new MyTranscoder();
TranscodingHints hints = new TranscodingHints();
hints.put(ImageTranscoder.KEY_WIDTH, 20f); //your image width
hints.put(ImageTranscoder.KEY_HEIGHT, 20f); //your image height
hints.put(ImageTranscoder.KEY_DOM_IMPLEMENTATION, SVGDOMImplementation.getDOMImplementation());
hints.put(ImageTranscoder.KEY_DOCUMENT_ELEMENT_NAMESPACE_URI, SVGConstants.SVG_NAMESPACE_URI);
hints.put(ImageTranscoder.KEY_DOCUMENT_ELEMENT, SVGConstants.SVG_SVG_TAG);
hints.put(ImageTranscoder.KEY_XML_PARSER_VALIDATING, false);
transcoder.setTranscodingHints(hints);
TranscoderInput input = new TranscoderInput(url.toExternalForm());
transcoder.transcode(input, null);
BufferedImage bufferedImage = transcoder.getImage();
4. Create an InputStream from BufferedImage
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
JPEGImageEncoder imageEncoder = JPEGCodec.createJPEGEncoder(outputStream);
imageEncoder.encode(bufferedImage);
byte[] bytes = outputStream.toByteArray();
InputStream inputStream = new ByteArrayInputStream(bytes);
5. Add the image to your ImageView
//javafx.scene.image.Image
Image image = new Image(inputStream);
//javafx.scene.image.ImageView
ImageView imageView = new ImageView();
imageView.setImage(image);
this.getChildren().add(imageView);
Hope this will help!

I used #pmoule's answer above, but had better luck replacing his steps 3-5 with this:
MyTranscoder imageTranscoder = new MyTranscoder();
imageTranscoder.addTranscodingHint(PNGTranscoder.KEY_WIDTH, (float) width);
imageTranscoder.addTranscodingHint(PNGTranscoder.KEY_HEIGHT, (float) height);
TranscoderInput input = new TranscoderInput(new FileReader(file));
imageTranscoder.transcode(input, null);
BufferedImage bimage = imageTranscoder.getImage();
WritableImage wimage = SwingFXUtils.toFXImage(bimage, null);
ImageView imageView = new ImageView(wimage);
<panel-vbox-whatever>.getChildren().clear();
<panel-vbox-whatever>.getChildren().add(imageView);
Simpler, and it just worked better for me.

Try http://forums.oracle.com/forums/thread.jspa?threadID=2264379&tstart=0

you do not need batik, you can try WebView like this:
WebView view = new WebView();
view.setMinSize(500, 400);
view.setPrefSize(500, 400);
final WebEngine eng = view.getEngine();
eng.load("http://127.0.0.1/demo1.svg");

Convert the SVG to FXML and then it becomes trivial. The conversion can be done with XSLT. You can get the stylesheet from here:
http://jayskills.com/blog/2012/06/03/svg-to-fxml-using-netbeans/
Then after conversion to FXML you can load it as a Node with the built-in FXMLLoader:
FXMLLoader.setDefaultClassLoader(this.getClass().getClassLoader());
URL location = KayakMain.class.getResource("path/to/my/resource.fxml");
Parent root = FXMLLoader.load(location);

Related

Android LibVLC getBitmap from a TextureView

I am trying to retrieve a frame from a video that is playing back using LibVLC in android. For reference, this is how I am starting LibVLC. ffmpegSv is a TextureView
public void startMediaPlayer() {
ArrayList<String> options = new ArrayList<>();
options.add("--no-drop-late-frames");
options.add("--no-skip-frames");
options.add("-vvv");
options.add("--no-osd");
options.add("--rtsp-tcp");
options.add("--no-snapshot-preview");
options.add("--no-video-title");
options.add("--no-spu");
videoVlc = new LibVLC(getActivity(), options);
TextureView surfaceView = (TextureView) getActivity().findViewById(R.id.streamView);
newVideoMediaPlayer = new org.videolan.libvlc.MediaPlayer(videoVlc);
final IVLCVout vOut = newVideoMediaPlayer.getVLCVout();
vOut.setVideoSurface(ffmpegSv.getSurfaceTexture());
vOut.setWindowSize(ffmpegSv.getWidth(), ffmpegSv.getHeight());
vOut.attachViews();
Media videoMedia = new Media (videoVlc, Uri.parse("rtsp://1.1.1.1/abc.mov"));
newVideoMediaPlayer.setMedia(videoMedia);
newVideoMediaPlayer.play();
}
And this is how I am attempting to get the bitmap from it. I should note this method worked correctly when using the android MediaPlayer.
#Override
public void onSurfaceTextureUpdated(SurfaceTexture surface) {
if (mStream != null) {
if (idx++ % 10 == 0) {
(new Runnable() {
#Override
public void run() {
FileOutputStream out = null;
Bitmap b = ffmpegSv.getBitmap(ffmpegSv.getWidth(), ffmpegSv.getHeight());
Bitmap bm = Bitmap.createScaledBitmap(b2, 640, 480, true);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
bm.compress(Bitmap.CompressFormat.JPEG, 50, bos);
byte[] arr = bos.toByteArray();
mStream.onJpegFrame(arr, 0L);
b.recycle();
bm.recycle();
}
}).run();
idx = 0;
}
}
}
However, the image that is being produced has a sliver of the original image from the TextureView around the edge almost like a border, but the rest of the image is obscured by a black box.
The only thing I can think of is that VLC uses some sort of overlay for subtitles etc that when pulled out with getBitmap() is losing its transparency. However, I am not 100% sure this is the case. Is there a way to check if this is the case, or disable any sort of overlays that VLC could be adding?
EDIT : I have added a sample image to demonstrate the problem:
You can just make out the bottom, right and top of the background image and a clear rectangle over the top of it.
Bitmap b = ffmpegSv.getBitmap(ffmpegSv.getWidth(), ffmpegSv.getHeight());
Bitmap bm = Bitmap.createScaledBitmap(b2, 640, 480, true);
Aren't you scaling something else here?
What is b2?

How to save an image in a set location?

I am trying to save a resized picture to the user's desktop but not sure how to do that.
Here's my code so far:
mi.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
String userhome = System.getProperty("user.home");
fileChooser = new JFileChooser(userhome + "\\Desktop");
fileChooser.setAutoscrolls(true);
switch (fileChooser.showOpenDialog(f)) {
case JFileChooser.APPROVE_OPTION:
BufferedImage img = null;
try {
img = ImageIO.read(fileChooser.getSelectedFile());
} catch (IOException e1) {
e1.printStackTrace();
}
Image dimg = img.getScaledInstance(f.getWidth(),
f.getHeight(), Image.SCALE_SMOOTH);
path = new ImageIcon(dimg);
configProps.setProperty("Path", fileChooser
.getSelectedFile().getPath());
imBg.setIcon(path);
break;
}
}
});
The code above resizes the imaged selected to fit the size of the JFrame then sets it to the JLabel.
This all works well but I also want to output the file to a set location lets say to the users desktop to make it easier. I'm currently looking at output stream but can't quite get my head around it.
Any help would be great.
Get the current Icon from the JLabel...
Icon icon = imgBg.getIcon();
Paint the icon to a BufferedImage...
BufferedImage img = new BufferedImage(icon.getIconWidth(), icon.getIconHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = img.createGraphics();
icon.paintIcon(null, g2d, 0, 0);
g2d.dispose();
Save the image to a file...
ImageIO.write(img, "png", new File("ResizedIcon.png"));
(and yes, you could use a JFileChooser to pick the file location/name)
You should also take a look at this for better examples of scaling an image, this way, you could scale the BufferedImage to another BufferedImage and save the hassle of having to re-paint the Icon
You might also like to take a look at Writing/Saving an Image
This is a example which is about saving images from Web to the local.
package cn.test.net;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
public class ImageRequest {
/**
* #param args
*/
public static void main(String[] args) throws Exception {
//a url from web
URL url = new URL("http://img.hexun.com/2011-06-21/130726386.jpg");
//open
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
//"GET"!
conn.setRequestMethod("GET");
//Timeout
conn.setConnectTimeout(5 * 1000);
//get data by InputStream
InputStream inStream = conn.getInputStream();
//to the binary , to save
byte[] data = readInputStream(inStream);
//a file to save the image
File imageFile = new File("BeautyGirl.jpg");
FileOutputStream outStream = new FileOutputStream(imageFile);
//write into it
outStream.write(data);
//close the Stream
outStream.close();
}
public static byte[] readInputStream(InputStream inStream) throws Exception{
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
//every time read length,if -1 ,end
int len = 0;
//a Stream read from buffer
while( (len=inStream.read(buffer)) != -1 ){
//mid parameter for starting position
outStream.write(buffer, 0, len);
}
inStream.close();
//return data
return outStream.toByteArray();
}
}
Hope this is helpful to you!

Error when decoding QR Code

I'm decoding an Qr Code that i'm getting throw the Java JSANE API. when i'm writing the image i got from the JSANE API in a file before reading it with IMAGEIO.read(), the decodong process is working but when i'm using the ilage Object given from the JSANE API directly without writing it in a file before reading, i' getting the following error :
Exception in thread "main" com.google.zxing.NotFoundException
The method i'm using are:
public String decode_QrCode(String filePath, String charset) throws FileNotFoundException, IOException, NotFoundException{
System.out.println("ICI ERREUR");
BinaryBitmap binaryBitmap = new BinaryBitmap(
new HybridBinarizer(
new BufferedImageLuminanceSource(
ImageIO.read(new FileInputStream(filePath))
)
)
);
Result qrCodeResult = new MultiFormatReader().decode(binaryBitmap);
return qrCodeResult.getText();
}
public String decode_QrCode_buffImg(BufferedImage bufferedImage) throws NotFoundException{
LuminanceSource source = new BufferedImageLuminanceSource(bufferedImage);
BinaryBitmap binaryBitmap = new BinaryBitmap(
new HybridBinarizer(
source
)
);
Result qrCodeResult = new MultiFormatReader().decode(binaryBitmap);
return qrCodeResult.getText();
}
I'm getting the image from the JSANE API like this:
Image image = dialog.openDialog();
I'm converting the Image to BufferedImage like this:
public static BufferedImage toBufferedImage(Image image)
{
if (image instanceof BufferedImage)
return (BufferedImage)image;
// This code ensures that all the pixels in the image are loaded
image = new ImageIcon(image).getImage();
// Determine if the image has transparent pixels
boolean hasAlpha = hasAlpha(image);
// Create a buffered image with a format that's compatible with the screen
BufferedImage bimage = null;
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
try {
// Determine the type of transparency of the new buffered image
int transparency = Transparency.OPAQUE;
if (hasAlpha == true)
transparency = Transparency.BITMASK;
// Create the buffered image
GraphicsDevice gs = ge.getDefaultScreenDevice();
GraphicsConfiguration gc = gs.getDefaultConfiguration();
bimage = gc.createCompatibleImage(image.getWidth(null), image.getHeight(null), transparency);
} catch (HeadlessException e) { } //No screen
if (bimage == null) {
// Create a buffered image using the default color model
int type = BufferedImage.TYPE_INT_RGB;
if (hasAlpha == true) {type = BufferedImage.TYPE_INT_ARGB;}
bimage = new BufferedImage(image.getWidth(null), image.getHeight(null), type);
}
// Copy image to buffered image
Graphics g = bimage.createGraphics();
// Paint the image onto the buffered image
g.drawImage(image, 0, 0, null);
g.dispose();
return bimage;
}
This the main function of the class:
public static void main(String[] args) throws IOException, cf, NotFoundException {
Frame frame = null;
// TODO Auto-generated method stub
JSaneDialog dialog = new JSaneDialog( JSaneDialog.CP_START_SANED_LOCALHOST,
frame, "JSaneDialog", true, null);
Image image = dialog.openDialog();
BufferedImage buffImg = toBufferedImage(image);
//BufferedImage buff = resize(buffImg, BufferedImage.TYPE_INT_RGB, buffImg.getWidth()/2, buffImg.getHeight()/2, 0.5, 0.5);
ImageIO.write(buffImg, "png", new File("/home/michaelyamsi/Bureau/Mémoires/test/test.png"));
QrCode New_Qr = new QrCode();
System.out.println("QR Code decompressed : " + New_Qr.decode_QrCode("/home/michaelyamsi/Bureau/Mémoires/test/test.png", "UTF-8"));
System.out.println("QR Code decompressed : " + New_Qr.decode_QrCode_buffImg(buffImg));
}
I'have even tried to resize th BufferedImage before using it but when i'm doing that, even the decode from the resultant file is not working.

Java/JavaFX: Set Swing Icon for JavaFX label

I'm trying to read a thumbnail (icon; 32x32px) from a file (.ico/.exe) and set it to a JavaFX label.
My first try:
public Icon getLargeIcon(String exeFile) {
if (exeFile != null) {
File file = new File(exeFile);
try {
ShellFolder sf = ShellFolder.getShellFolder(file);
return new ImageIcon(sf.getIcon(true), sf.getFolderType());
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
return null;
}
After that I'm doing this:
Icon largeIcon = getLargeIcon(file.getAbsolutePath());
ImageIcon swingImageIcon = (ImageIcon) largeIcon;
java.awt.Image awtImage = swingImageIcon.getImage();
Image fxImage = javafx.scene.image.Image.impl_fromPlatformImage(awtImage);
lblAppIconValue.setGraphic(new ImageView(fxImage));
I've searched trough several sites and found this, but it gives me an exception:
java.lang.UnsupportedOperationException: unsupported class for loadPlatformImage
My second try:
URL url = file.toURI().toURL();
Image image = new Image(url.toString());
lblAppIconValue.setGraphic(new ImageView(image));
Also not working ...
My question: How can I set a javax.swing.Icon to a JavaFX label? Is it possible? If it's not possible, how can I read a thumbnail from a file and set it as an icon/graphic for a JavaFX label?
Thanks!
Never use impl_ methods: these are not part of the public API.
To convert an awt Image to an FX Image, the SwingFXUtils class in javafx.embed.swing has a toFXImage(...) method that converts a BufferedImage to a JavaFX Image. It's not clear whether the image you have from the icon is a BufferedImage, so you'll need a couple of steps to make that work:
BufferedImage bImg ;
if (awtImage instanceof BufferedImage) {
bImg = (BufferedImage) awtImage ;
} else {
bImg = new BufferedImage(awtImage.getWidth(null), awtImage.getHeight(null), BufferedImage.TYPE_INT_ARGB);
Graphics2D graphics = bImg.createGraphics();
graphics.drawImage(awtImage, 0, 0, null);
graphics.dispose();
}
Image fxImage = SwingFXUtils.toFXImage(bImg, null);
This is a fairly inefficient approach, as you are first creating an awt image from your file, then converting it to an FX image, possibly via an intermediate buffered image. If you have access to the source code for the ShellFolder class, you might see how that implements the getIcon() method and follow the same process. At some point, it must get an InputStream with the image data; once you have that you can pass it to the javafx.scene.image.Image constructor.
If you want to place an image in your application on JavaFX you have 2 main options:
Define it in fxml:
<ImageView>
<Image url="icon.png"/>
</ImageView>
Create Label in your controller:
import javafx.scene.control.Label;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
...
Image image = new Image(getClass().getResourceAsStream("icon.png"));
Label label = new Label("Label");
label.setGraphic(new ImageView(image));
icon.png should be placed in the same package with fxml-file or your controller (otherwise you should amend image name in that example).
Update: change image in label dynamically (in accordance with image selected by user).
fxml:
<Button fx:id="setImageButton"/>
<ImageView fx:id="image">
<Image url="defaultImage.png"/>
</ImageView>
Controller:
public class MainController implements Initializable {
public Parent root;
public Button setImageButton;
public ImageView image;
#Override
public void initialize(URL location, ResourceBundle resources) {
setImageButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
FileChooser fileChooser = new FileChooser();
File file = fileChooser.showOpenDialog(root.getScene().getWindow());
if (file != null) {
try {
BufferedImage bufferedImage = ImageIO.read(file);
Image picture = SwingFXUtils.toFXImage(bufferedImage, null);
image.setImage(picture);
} catch (IOException ex) {
// do something
}
}
}
});
}
}

Getting a black screen after trying to resize an image

I am currently trying to resize a picture that I am downloading from the web and putting it into a JPanel.
First, I am using the following code to download the image from the web:
public static Image MSImageHigh(){
URL imageUrl = null;
try {
imageUrl = new URL("http://www.hmdb.ca/labm/metabolites/"
+ HMDB + "/ms/spectraH/" + HMDB + "H.png");
} catch (MalformedURLException e) {
e.printStackTrace();
}
Image image = Toolkit.getDefaultToolkit().createImage(imageUrl);
return image;
}
Then I made a new method that resizes the image:
public static BufferedImage resizeImage() {
final BufferedImage bufferedImage = new BufferedImage(300, 500,BufferedImage.TYPE_INT_RGB);
final Graphics2D graphics2D = bufferedImage.createGraphics();
graphics2D.setComposite(AlphaComposite.Src);
graphics2D.drawImage(MSImageHigh(), 0, 0, 200, 200, null);
graphics2D.dispose();
return bufferedImage;
}
This should produce s a new image that is resized to 200x200 px. What it in fact does is give me a black screen that is 200x200px in size. Btw, I also tried using TYPE_INT_ARGB instead of TYPE_INT_RGB, and this produces a totally transparent image, so that is not working either.
I used ImageIO.read(imageUrl) instead of Toolkit.getDefaultToolkit().createImage(imageUrl) and that solved the problem. Thanks #Hovercraft Full Of Eels!

Categories