mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/jpexs-decompiler.git
synced 2026-06-06 06:37:10 +00:00
Added #2079 Bulk import sprites from GIFs
This commit is contained in:
@@ -4,7 +4,7 @@ All notable changes to this project will be documented in this file.
|
||||
## [Unreleased]
|
||||
### Added
|
||||
- [#2090] Support for Mochicrypt packed binarydata tags - loading SWF as subtree
|
||||
- [#2079] Replace DefineSprite with GIF
|
||||
- [#2079] Replace DefineSprite with GIF, Bulk import sprites from GIFs
|
||||
|
||||
## [19.0.0] - 2023-10-01
|
||||
### Added
|
||||
|
||||
@@ -924,6 +924,9 @@ public final class Configuration {
|
||||
@ConfigurationDefaultBoolean(true)
|
||||
public static ConfigurationItem<Boolean> lastFlaExportCompressed = null;
|
||||
|
||||
@ConfigurationDefaultBoolean(true)
|
||||
@ConfigurationCategory("ui")
|
||||
public static ConfigurationItem<Boolean> showImportSpriteInfo = null;
|
||||
private enum OSId {
|
||||
WINDOWS, OSX, UNIX
|
||||
}
|
||||
|
||||
@@ -22,20 +22,27 @@ import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.tags.DefineShape2Tag;
|
||||
import com.jpexs.decompiler.flash.tags.DefineSpriteTag;
|
||||
import com.jpexs.decompiler.flash.tags.PlaceObject2Tag;
|
||||
import com.jpexs.decompiler.flash.tags.RemoveObjectTag;
|
||||
import com.jpexs.decompiler.flash.tags.ShowFrameTag;
|
||||
import com.jpexs.decompiler.flash.tags.Tag;
|
||||
import com.jpexs.decompiler.flash.tags.base.CharacterIdTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.CharacterTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.PlaceObjectTypeTag;
|
||||
import com.jpexs.decompiler.flash.timeline.Timelined;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FilenameFilter;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import javax.imageio.ImageIO;
|
||||
|
||||
/**
|
||||
@@ -145,4 +152,70 @@ public class SpriteImporter {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public int bulkImport(File spritesDir, SWF swf, boolean printOut) {
|
||||
Map<Integer, CharacterTag> characters = swf.getCharacters();
|
||||
int spriteCount = 0;
|
||||
List<String> extensions = Arrays.asList("gif");
|
||||
File allFiles[] = spritesDir.listFiles(new FilenameFilter() {
|
||||
@Override
|
||||
public boolean accept(File dir, String name) {
|
||||
String nameLower = name.toLowerCase();
|
||||
for (String ext : extensions) {
|
||||
if (nameLower.endsWith("." + ext)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
for (int characterId : characters.keySet()) {
|
||||
CharacterTag tag = characters.get(characterId);
|
||||
if (tag instanceof DefineSpriteTag) {
|
||||
DefineSpriteTag spriteTag = (DefineSpriteTag) tag;
|
||||
List<File> existingFilesForSpriteTag = new ArrayList<>();
|
||||
for (File f : allFiles) {
|
||||
if (f.getName().startsWith("" + characterId + ".") || f.getName().startsWith("" + characterId + "_")) {
|
||||
existingFilesForSpriteTag.add(f);
|
||||
}
|
||||
}
|
||||
existingFilesForSpriteTag.sort(new Comparator<File>() {
|
||||
@Override
|
||||
public int compare(File o1, File o2) {
|
||||
String ext1 = o1.getName().substring(o1.getName().lastIndexOf(".") + 1);
|
||||
String ext2 = o2.getName().substring(o2.getName().lastIndexOf(".") + 1);
|
||||
int ret = extensions.indexOf(ext1) - extensions.indexOf(ext2);
|
||||
if (ret == 0) {
|
||||
return o1.getName().compareTo(o2.getName());
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
});
|
||||
|
||||
if (existingFilesForSpriteTag.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (existingFilesForSpriteTag.size() > 1) {
|
||||
Logger.getLogger(SpriteImporter.class.getName()).log(Level.WARNING, "Multiple matching files for sprite tag {0} exists, {1} selected", new Object[]{characterId, existingFilesForSpriteTag.get(0).getName()});
|
||||
}
|
||||
File sourceFile = existingFilesForSpriteTag.get(0);
|
||||
|
||||
if (printOut) {
|
||||
System.out.println("Importing character " + characterId + " from file " + sourceFile.getName());
|
||||
}
|
||||
|
||||
try(FileInputStream fis = new FileInputStream(sourceFile.getAbsolutePath())) {
|
||||
importSprite(spriteTag, fis);
|
||||
spriteCount++;
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(ShapeImporter.class.getName()).log(Level.WARNING, "Cannot import sprite " + characterId + " from file " + sourceFile.getName(), ex);
|
||||
}
|
||||
if (Thread.currentThread().isInterrupted()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return spriteCount;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -380,6 +380,16 @@ public abstract class MainFrameMenu implements MenuBuilder {
|
||||
}
|
||||
mainFrame.getPanel().importShape((SWF) openable, true);
|
||||
}
|
||||
|
||||
protected void importSpritesActionPerformed(ActionEvent evt) {
|
||||
if (Main.isWorking()) {
|
||||
return;
|
||||
}
|
||||
if (mainFrame.getPanel().checkEdited()) {
|
||||
return;
|
||||
}
|
||||
mainFrame.getPanel().importSprite((SWF) openable);
|
||||
}
|
||||
|
||||
protected void importMoviesActionPerformed(ActionEvent evt) {
|
||||
if (Main.isWorking()) {
|
||||
@@ -1031,6 +1041,7 @@ public abstract class MainFrameMenu implements MenuBuilder {
|
||||
setMenuEnabled("/import/importtab/importText", allSameSwf && swfSelected && !isWorking);
|
||||
setMenuEnabled("/import/importtab/importScript", allSameOpenable && openableSelected && !isWorking);
|
||||
setMenuEnabled("/import/importtab/importImages", allSameSwf && swfSelected && !isWorking);
|
||||
setMenuEnabled("/import/importtab/importSprites", allSameSwf && swfSelected && !isWorking);
|
||||
setMenuEnabled("/import/importtab/importShapes", allSameSwf && swfSelected && !isWorking);
|
||||
setMenuEnabled("/import/importtab/importShapesNoFill", allSameSwf && swfSelected && !isWorking);
|
||||
setMenuEnabled("/import/importtab/importMovies", allSameSwf && swfSelected && !isWorking);
|
||||
@@ -1164,6 +1175,7 @@ public abstract class MainFrameMenu implements MenuBuilder {
|
||||
addMenuItem("/import/importtab/importImages", translate("menu.file.import.image"), "importimage32", this::importImagesActionPerformed, PRIORITY_MEDIUM, null, true, null, false);
|
||||
addMenuItem("/import/importtab/importShapes", translate("menu.file.import.shape"), "importshape32", this::importShapesActionPerformed, PRIORITY_MEDIUM, null, true, null, false);
|
||||
addMenuItem("/import/importtab/importShapesNoFill", translate("menu.file.import.shapeNoFill"), "importshape32", this::importShapesNoFillActionPerformed, PRIORITY_MEDIUM, null, true, null, false);
|
||||
addMenuItem("/import/importtab/importSprites", translate("menu.file.import.sprite"), "importsprite32", this::importSpritesActionPerformed, PRIORITY_MEDIUM, null, true, null, false);
|
||||
addMenuItem("/import/importtab/importMovies", translate("menu.file.import.movie"), "importmovie32", this::importMoviesActionPerformed, PRIORITY_MEDIUM, null, true, null, false);
|
||||
addMenuItem("/import/importtab/importSounds", translate("menu.file.import.sound"), "importsound32", this::importSoundsActionPerformed, PRIORITY_MEDIUM, null, true, null, false);
|
||||
addMenuItem("/import/importtab/importSymbolClass", translate("menu.file.import.symbolClass"), "importsymbolclass32", this::importSymbolClassActionPerformed, PRIORITY_MEDIUM, null, true, null, false);
|
||||
|
||||
@@ -3389,6 +3389,65 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se
|
||||
}.execute();
|
||||
}
|
||||
}
|
||||
|
||||
public void importSprite(final SWF swf) {
|
||||
ViewMessages.showMessageDialog(MainPanel.this, translate("message.info.importSprites"), translate("message.info"), JOptionPane.INFORMATION_MESSAGE, Configuration.showImportSpriteInfo);
|
||||
JFileChooser chooser = new JFileChooser();
|
||||
chooser.setCurrentDirectory(new File(Configuration.lastExportDir.get()));
|
||||
chooser.setDialogTitle(translate("import.select.directory"));
|
||||
chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
|
||||
chooser.setAcceptAllFileFilterUsed(false);
|
||||
if (chooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
|
||||
String selFile = Helper.fixDialogFile(chooser.getSelectedFile()).getAbsolutePath();
|
||||
File spritesDir = new File(Path.combine(selFile, SpriteExportSettings.EXPORT_FOLDER_NAME));
|
||||
if (!spritesDir.exists()) {
|
||||
spritesDir = new File(selFile);
|
||||
}
|
||||
final File fSpritesDir = spritesDir;
|
||||
SpriteImporter spriteImporter = new SpriteImporter();
|
||||
|
||||
final long timeBefore = System.currentTimeMillis();
|
||||
new CancellableWorker<Void>() {
|
||||
|
||||
private int count = 0;
|
||||
|
||||
@Override
|
||||
public Void doInBackground() throws Exception {
|
||||
try {
|
||||
count = spriteImporter.bulkImport(fSpritesDir, swf, false);
|
||||
swf.clearImageCache();
|
||||
swf.clearShapeCache();
|
||||
} catch (Exception ex) {
|
||||
logger.log(Level.SEVERE, "Error during import", ex);
|
||||
ViewMessages.showMessageDialog(null, translate("error.import") + ": " + ex.getClass().getName() + " " + ex.getLocalizedMessage());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStart() {
|
||||
Main.startWork(translate("work.importing") + "...", this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void done() {
|
||||
Main.stopWork();
|
||||
long timeAfter = System.currentTimeMillis();
|
||||
final long timeMs = timeAfter - timeBefore;
|
||||
|
||||
View.execInEventDispatch(() -> {
|
||||
refreshTree(swf);
|
||||
setStatus(translate("import.finishedin").replace("%time%", Helper.formatTimeSec(timeMs)));
|
||||
|
||||
ViewMessages.showMessageDialog(MainPanel.this, translate("import.sprite.result").replace("%count%", Integer.toString(count)));
|
||||
if (count != 0) {
|
||||
reload(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
}.execute();
|
||||
}
|
||||
}
|
||||
|
||||
public void importShape(final SWF swf, boolean noFill) {
|
||||
ViewMessages.showMessageDialog(MainPanel.this, translate("message.info.importShapes2"), translate("message.info"), JOptionPane.INFORMATION_MESSAGE, Configuration.showImportShapeInfo);
|
||||
@@ -4439,7 +4498,7 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se
|
||||
}
|
||||
}
|
||||
|
||||
public void replaceWithGifButtonActionPerformed(TreeItem item) {
|
||||
public void replaceSpriteWithGifButtonActionPerformed(TreeItem item) {
|
||||
if (item == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -403,7 +403,7 @@ public class PreviewPanel extends JPersistentSplitPane implements TagEditorPanel
|
||||
replaceSpriteButton.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
mainPanel.replaceWithGifButtonActionPerformed(mainPanel.getCurrentTree().getCurrentTreeItem());
|
||||
mainPanel.replaceSpriteWithGifButtonActionPerformed(mainPanel.getCurrentTree().getCurrentTreeItem());
|
||||
}
|
||||
});
|
||||
replaceSpriteButton.setVisible(false);
|
||||
|
||||
BIN
src/com/jpexs/decompiler/flash/gui/graphics/importsprite16.png
Normal file
BIN
src/com/jpexs/decompiler/flash/gui/graphics/importsprite16.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.9 KiB |
BIN
src/com/jpexs/decompiler/flash/gui/graphics/importsprite32.png
Normal file
BIN
src/com/jpexs/decompiler/flash/gui/graphics/importsprite32.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 8.2 KiB |
@@ -704,3 +704,7 @@ config.description.lastFlaExportVersion = Last exported FLA version
|
||||
|
||||
config.name.lastFlaExportCompressed = Last FLA export compressed
|
||||
config.description.lastFlaExportCompressed = Last exported FLA version compressed
|
||||
|
||||
#after 19.0.0
|
||||
config.name.showImportSpriteInfo = Show information before importing sprites
|
||||
config.description.showImportSpriteInfo = Displays some info about how importing sprites works after clicking Import sprites in the menu.
|
||||
|
||||
@@ -1162,4 +1162,12 @@ button.abcexploretrait = Show trait in ABC Explorer
|
||||
#after 19.0.0
|
||||
binarydata.swfInside.packer = It looks like there is SWF inside this binary data tag packed with %packer%. Click here to unpack the SWF and load it as subtree.
|
||||
|
||||
button.replaceWithGif = Replace with GIF...
|
||||
button.replaceWithGif = Replace with GIF...
|
||||
|
||||
message.info.importSprites = During importing sprites, you need to select a FOLDER.\r\n \
|
||||
The folder must contain "sprites" subfolder and filenames inside must match existing sprites in current selected SWF.\r\n \
|
||||
Each file must have ".gif" extension.
|
||||
|
||||
import.sprite.result = %count% sprites imported.
|
||||
|
||||
menu.file.import.sprite = Import sprites from GIF
|
||||
@@ -363,7 +363,7 @@ public class TagTreeContextMenu extends JPopupMenu {
|
||||
replaceWithGifMenuItem.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
mainPanel.replaceWithGifButtonActionPerformed(getCurrentItem());
|
||||
mainPanel.replaceSpriteWithGifButtonActionPerformed(getCurrentItem());
|
||||
}
|
||||
});
|
||||
replaceWithGifMenuItem.setIcon(View.getIcon("replacesprite16"));
|
||||
|
||||
Reference in New Issue
Block a user