Abwerfen der Bild -URL von Webbrowser in der Java -App funktioniert nicht für macOS
Posted: 10 Feb 2025, 10:23
meine Java (Java 21) -Anwendung hat einen Teil der GUI, mit dem Sie ein Bild in Google im Webbrowser in die Anwendung ziehen können. Nachricht ist auch protokolliert. Nichts ist sogar protokolliert. Basierend auf Vorschlag VGR I Logge jetzt, wenn es eine Ausnahme gibt, und auch log EM> Methode so scheint es, dass MacOS den Drag -Tropfen verhindert, bevor er überhaupt zu meinem Code kommt . Vom Finder stattdessen
Was verursacht den Unterschied? em> < /p>
update
Das synchronisierte Schlüsselwort entfernt, wie von VGR vorgeschlagen, wird nun in Drop, wirft aber eine Ausnahme aus
Mögliches zugehöriges Problem - https://bugs.openjdk.org/browse/jdk-4358053
Update 2 < /p>
, wie auch durch VGR vorgeschlagen wurde, hat mehrere Anrufe nach GetTransferData () entfernt. Daher kann er nur einmal pro Aufruf der Methode aufgerufen werden, machte keinen Unterschied. < /p>
Update 3
Sehen Sie sich die verfügbaren Datenaromen an und tauschten die Anweisung iF aus, sodass es nach
sucht
Und dann funktioniert es.
Für einen Geschmack, den er berichtet hatte, und bevor ich eine andere Verarbeitung durchführte, dass dies tatsächlich ein Fehler in dem Code ist, der Java für macOS
Was verursacht den Unterschied? em> < /p>
Code: Select all
package com.jthink.songkong.ui.startdialog.editsongs;
import com.jthink.songkong.analyse.general.ArtworkHelper;
import com.jthink.songkong.analyse.musicbrainz.RemoteArtworkLookup;
import com.jthink.songkong.db.ImageCache;
import com.jthink.songkong.db.SongCache;
import com.jthink.songkong.preferences.UserOption;
import com.jthink.songkong.preferences.UserPreferences;
import com.jthink.songkong.ui.MainWindow;
import com.jthink.songkong.ui.startdialog.imagefilters.ImageFileFilter;
import com.jthink.songkong.ui.startdialog.imagefilters.ImageFilterFactory;
import com.jthink.songlayer.CoverImage;
import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.stream.MemoryCacheImageOutputStream;
import javax.swing.*;
import java.awt.*;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.dnd.DnDConstants;
import java.awt.dnd.DropTarget;
import java.awt.dnd.DropTargetDropEvent;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URL;
import java.nio.file.Files;
import java.util.logging.Level;
import static com.jthink.songkong.ui.startdialog.editsongs.ArtworkTab.ARTWORK_SIZE;
import static com.jthink.songkong.ui.startdialog.editsongs.ImageSizeDefaults.MAX_IMAGE_SIZE;
import static com.jthink.songkong.ui.startdialog.editsongs.ImageSizeDefaults.MIN_IMAGE_SIZE;
public class ArtworkDropTarget extends DropTarget
{
private static CoverImage coverImage;
private JLabel displayArtwork;
public static DataFlavor uriListFlavor; //This is used by Linux for loading files
public static DataFlavor imageFlavor; //This is used by Firefox, when drag single image file
public static DataFlavor urlFlavour; //This is used by Firefox, when drag single image file
public static DataFlavor pictImageFlavor; //This is used by OSX for iTunes
public static DataFlavor imageIconDataFlavor; //When dragging from existingArtwork
static
{
try
{
uriListFlavor = new DataFlavor("text/uri-list;class=java.lang.String");
urlFlavour = new DataFlavor("application/x-java-url;class=java.net.URL");
imageFlavor = new DataFlavor("image/x-java-image;class=java.awt.Image");
pictImageFlavor = new DataFlavor("image/x-pict;class=java.io.InputStream");
imageIconDataFlavor = new DataFlavor(DataFlavor.javaJVMLocalObjectMimeType +
";class=\""+javax.swing.Icon.class.getName() + "\"");
}
catch (ClassNotFoundException cne)
{
throw new RuntimeException("unable to create uri-list flavor in drop target:" + cne.getMessage());
}
}
public ArtworkDropTarget(Component c, JLabel displayArtwork)
throws HeadlessException
{
super(c, DnDConstants.ACTION_COPY, null, true, null);
this.displayArtwork= displayArtwork;
}
public static void setCoverImage(CoverImage coverImage)
{
ArtworkDropTarget.coverImage = coverImage;
}
/**
* When used as Drop target
*
* @param dtde
*/
public synchronized void drop(DropTargetDropEvent dtde)
{
MainWindow.logger.severe("Starting Drop");
dtde.acceptDrop(DnDConstants.ACTION_COPY);
Transferable trans = dtde.getTransferable();
try
{
if (trans.isDataFlavorSupported(imageIconDataFlavor))
{
MainWindow.logger.severe("Received ImageIcon:"+trans.getTransferData(imageIconDataFlavor));
ImageIconWithOriginalImage icon = (ImageIconWithOriginalImage)trans.getTransferData(imageIconDataFlavor);
setExistingArtwork((BufferedImage)icon.getOriginalImage());
}
else if (trans.isDataFlavorSupported(DataFlavor.javaFileListFlavor) && ImageFilterFactory.getImageFilter().accept(((java.util.List) trans.getTransferData(DataFlavor.javaFileListFlavor)).get(0)))
{
MainWindow.logger.severe("Received Files:"+trans.getTransferData(DataFlavor.javaFileListFlavor));
File file = ((java.util.List) trans.getTransferData(DataFlavor.javaFileListFlavor)).get(0);
setExistingArtwork(file);
}
else if (trans.isDataFlavorSupported(imageFlavor) && trans.getTransferData(ArtworkDropTarget.imageFlavor) instanceof BufferedImage)
{
MainWindow.logger.severe("Received Image:"+trans.getTransferData(ArtworkDropTarget.imageFlavor));
setExistingArtwork((BufferedImage)trans.getTransferData(ArtworkDropTarget.imageFlavor));
}
else if (trans.isDataFlavorSupported(urlFlavour))
{
URI imageUri = ((URL) trans.getTransferData(ArtworkDropTarget.urlFlavour)).toURI();
MainWindow.logger.severe("Received ImageUrl:" + imageUri);
URI subUri = GoogleImageSearch.getImageUrlFromImageSearchUrl(imageUri);
if (GoogleImageSearch.isGoogleImageSearch(imageUri) && subUri!=null)
{
MainWindow.logger.severe("Received ImageSubUrl:" + subUri);
setExistingArtwork(subUri);
}
else
{
MainWindow.logger.severe("Received ImageUrl:" + imageUri);
setExistingArtwork(imageUri);
}
}
else
{
MainWindow.logger.severe("Unknown DataFlavor for ImageUrl");
for(DataFlavor next:trans.getTransferDataFlavors())
{
MainWindow.logger.severe(next.toString());
}
}
dtde.dropComplete(true);
}
catch(Exception ex)
{
MainWindow.logger.log(Level.SEVERE, ex.getMessage(), ex);
dtde.dropComplete(false);
}
}
/**
* TODO do we have to convert to JPG, cant we keep as PNG
* @param image
*/
private void setExistingArtwork(BufferedImage image)
{
try
{
byte[] imageData = writeCompressedJpegImageToByteArray(image, 1.0f);
coverImage = ImageCache.saveNewCoverImage(image, imageData, "internet", com.jthink.songlayer.CoverImage.createKeyFromData(imageData),
MIN_IMAGE_SIZE,
UserOption.ARTWORK_MAX_SIZE.getIntValue()
);
SongCache.saveImagesForReport(coverImage, null);
createNewArtworkImage(image);
}
catch (IOException ex)
{
MainWindow.logger.log(Level.SEVERE, ex.getMessage(), ex);
}
}
/**
* Write Compressed Jpeg, use minimum compression of 1f for best quality
*
* @param bi
* @param compressionLevel
* @return
* @throws IOException
*/
private static byte[] writeCompressedJpegImageToByteArray(BufferedImage bi, float compressionLevel) throws IOException
{
ImageWriter imageWriter = ImageIO.getImageWritersByFormatName( "jpg").next();
ImageWriteParam writeParams = imageWriter.getDefaultWriteParam();
writeParams.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
writeParams.setCompressionQuality(compressionLevel);
final ByteArrayOutputStream output = new ByteArrayOutputStream();
imageWriter.setOutput( new MemoryCacheImageOutputStream(output));
IIOImage outputImage = new IIOImage(bi, null, null);
imageWriter.write(null, outputImage, writeParams);
imageWriter.dispose();
output.flush();
final byte[] imageData = output.toByteArray();
return imageData;
}
/**
*
* @param imageUri
*/
private void setExistingArtwork(URI imageUri)
{
byte[] imageData = RemoteArtworkLookup.getDirectImage(imageUri.toString());
if (imageData != null)
{
BufferedImage image = ArtworkHelper.createBufferedImageFromRawData(imageData, imageUri.toString());
coverImage = ImageCache.saveNewCoverImage(image, imageData, "internet", com.jthink.songlayer.CoverImage.createKeyFromData(imageData),
UserPreferences.getInstance().getMinImageSize(),
(Integer) UserOption.ARTWORK_MAX_SIZE.getUserPref().getValue());
SongCache.saveImagesForReport(coverImage, null);
createNewArtworkImage(image);
}
else
{
MainWindow.logger.severe("Unable To Decode Image:"+imageUri.toString());
}
}
/**
*
* @param file
*/
private void setExistingArtwork(File file)
{
try
{
ImageFileFilter iff = ImageFilterFactory.getImageFilter();
if(iff.accept(file))
{
byte[] imageData = Files.readAllBytes(file.toPath());
BufferedImage image = ArtworkHelper.createBufferedImageFromRawData(imageData, file.getName());
coverImage = ImageCache.saveNewCoverImage(image, imageData, file.getName(),
com.jthink.songlayer.CoverImage.createKeyFromData(imageData),
UserPreferences.getInstance().getMinImageSize(),
(Integer) UserOption.ARTWORK_MAX_SIZE.getUserPref().getValue());
SongCache.saveImagesForReport(coverImage, null);
createNewArtworkImage(image);
}
}
catch(Exception ex)
{
MainWindow.logger.log(Level.SEVERE, ex.getMessage(), ex);
}
}
/**
* Update new artwork label with version of this image
*
* @param image
*/
private void createNewArtworkImage(BufferedImage image)
{
BufferedImage ret = new BufferedImage(ARTWORK_SIZE, ARTWORK_SIZE, BufferedImage.TYPE_INT_RGB);
ret.getGraphics().drawImage(image, 0, 0, ARTWORK_SIZE, ARTWORK_SIZE, null);
ImageIcon ii = new ImageIcon(ret);
displayArtwork.setIcon(ii);
displayArtwork.setText(image.getWidth() + " x " + image.getHeight());
ArtworkFont.formatArtworkLabel(displayArtwork);
}
public static CoverImage getCoverImage()
{
return coverImage;
}
}
Das synchronisierte Schlüsselwort entfernt, wie von VGR vorgeschlagen, wird nun in Drop, wirft aber eine Ausnahme aus
Code: Select all
01/2025 12.52.09:GMT:ArtworkDropTarget:drop:SEVERE: Cannot invoke "String.length()" because "spec" is null
java.awt.dnd.InvalidDnDOperationException: Cannot invoke "String.length()" because "spec" is null
at java.desktop/sun.awt.dnd.SunDropTargetContextPeer.getTransferData(SunDropTargetContextPeer.java:274)
at java.desktop/sun.awt.datatransfer.TransferableProxy.getTransferData(TransferableProxy.java:73)
at java.desktop/java.awt.dnd.DropTargetContext$TransferableProxy.getTransferData(DropTargetContext.java:387)
at com.jthink.songkong.ui.startdialog.editsongs.ArtworkDropTarget.drop(ArtworkDropTarget.java:109)
at java.desktop/sun.awt.dnd.SunDropTargetContextPeer.processDropMessage(SunDropTargetContextPeer.java:548)
at java.desktop/sun.lwawt.macosx.CDropTargetContextPeer.processDropMessage(CDropTargetContextPeer.java:129)
at java.desktop/sun.awt.dnd.SunDropTargetContextPeer$EventDispatcher.dispatchDropEvent(SunDropTargetContextPeer.java:864)
at java.desktop/sun.awt.dnd.SunDropTargetContextPeer$EventDispatcher.dispatchEvent(SunDropTargetContextPeer.java:788)
at java.desktop/sun.awt.dnd.SunDropTargetEvent.dispatch(SunDropTargetEvent.java:48)
at java.desktop/java.awt.Component.dispatchEventImpl(Component.java:4861)
at java.desktop/java.awt.Container.dispatchEventImpl(Container.java:2324)
at java.desktop/java.awt.Component.dispatchEvent(Component.java:4828)
at java.desktop/java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4948)
at java.desktop/java.awt.LightweightDispatcher.processDropTargetEvent(Container.java:4649)
at java.desktop/java.awt.LightweightDispatcher.dispatchEvent(Container.java:4511)
at java.desktop/java.awt.Container.dispatchEventImpl(Container.java:2310)
at java.desktop/java.awt.Window.dispatchEventImpl(Window.java:2780)
at java.desktop/java.awt.Component.dispatchEvent(Component.java:4828)
at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:775)
at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:720)
at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:714)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:400)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:87)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:98)
at java.desktop/java.awt.EventQueue$5.run(EventQueue.java:747)
at java.desktop/java.awt.EventQueue$5.run(EventQueue.java:745)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:400)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:87)
at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:744)
at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)
Update 2 < /p>
, wie auch durch VGR vorgeschlagen wurde, hat mehrere Anrufe nach GetTransferData () entfernt. Daher kann er nur einmal pro Aufruf der Methode aufgerufen werden, machte keinen Unterschied. < /p>
Update 3
Sehen Sie sich die verfügbaren Datenaromen an und tauschten die Anweisung iF aus, sodass es nach
sucht
Code: Select all
uriListFlavor = new DataFlavor("text/uri-list;class=java.lang.String");
< /code>
vor < /p>
urlFlavour = new DataFlavor("application/x-java-url;class=java.net.URL");
Code: Select all
java.awt.dnd.InvalidDnDOperationException: Cannot invoke "String.length()" because "spec" is null
at java.desktop/sun.awt.dnd.SunDropTargetContextPeer.getTransferData(SunDropTargetContextPeer.java:274)
at java.desktop/sun.awt.datatransfer.TransferableProxy.getTransferData(TransferableProxy.java:73)
at java.desktop/java.awt.dnd.DropTargetContext$TransferableProxy.getTransferData(DropTargetContext.java:387)