Resource icon

PalApply v2 2.0.3

No permission to download
Does anyone know of some gif editor that has similar feature built in, im wondering why Plombo wasnt asked to license his code into some pixel art editors, palapply is a piece of genius software.
Aseprite has huge issue with converting to indexed, it would be great if palapply would be merged into it like rotsprite is .
OK i figured out a way to remap palette from other file to new animation in aseprite, so thats handy.Its not as precise as palapply tho.
 
Plombo said:
Hey everyone. I rewrote my 10 year old program PalApply to support alpha masks and write well-optimized PNG output. I quietly released a replacement for the command line PalApply a year or two ago, but now I've gotten around to a full replacement for the GUI version that most people use.

Differences from the original PalApply, copied from the PalApply v2 readme:
  • If the source image has non-trivial alpha (partial transparency), then in addition to the usual indexed image, PalApply v2 will save a corresponding alpha mask that can be used with OpenBOR's alphamask command.
  • If the source image has any transparency at all, fully transparent pixels will be mapped to the transparent color (the first color in the palette).
  • The palette must be specified using an image file; there is no longer support for palettes in .pal/.act/.gpl format.
  • [since v2.0.1] The palette must be an image in PNG or GIF format or a palette in .act format; there is no longer support for palettes in .pal/.gpl format.
  • All output is in PNG format. GIF, PCX, and BMP are still supported as input formats, just not for output.
  • As a tradeoff for the above, the PNGs written by PalApply v2 are compressed to a small file size and optimized for fast loading. This is in sharp contrast to the poorly encoded PNGs written by the original PalApply, which were often larger than the equivalent GIFs.
  • The user interface of PalApply v2 is similar to that of its predecessor, but is more polished in various ways.
  • PalApply v2 is written in C rather than Java, so it doesn't require the Java runtime to be installed.

Everything else is about the same as the old PalApply; the interface is prettier but works the same. The only potentially contentious change is PalApply v2's inability to write GIF output. The only reason to use GIF over PNG is that GIFs load a bit faster, but the next release of OpenBOR will have my rewritten PNG decoder. With that, the optimized PNGs written by PalApply v2 load slightly faster than their GIF equivalents, so there will no longer be any reason to use GIF. If, in spite of all that, you still really want GIF output for whatever reason, you can still just use the original PalApply. It's not going anywhere.

With all that said, you can download PalApply v2 at the GitHub releases page. It supports Windows and Linux, but for Linux you'll have to compile it yourself.

I'm not aware of any issues with it, but it hasn't been tested as much as the original PalApply, so let me know if you find any issues.

Enjoy! ;D

Amigo Plobo, what is this PalApply v2.0.3 program for? does it transform the png sprites that I cut in the gimp into alpha?
 
Amigo Plombo, what is this PalApply v2.0.3 program for? does it transform the png sprites that I cut in the gimp into alpha?
 
Plombo: Sadly, it seems that the PalApply 1.0 is broken. Here is the error meassage:
Code:
- Reading palette file...
- Palette read successfully!
java.io.FileNotFoundException: C:\Users\Fred\Documents\convert\exported\a100.gif (Accès refusé)
        at java.io.RandomAccessFile.open0(Native Method)
        at java.io.RandomAccessFile.open(Unknown Source)
        at java.io.RandomAccessFile.<init>(Unknown Source)
        at javax.imageio.stream.FileImageOutputStream.<init>(Unknown Source)
        at com.sun.imageio.spi.FileImageOutputStreamSpi.createOutputStreamInstance(Unknown Source)
        at javax.imageio.ImageIO.createImageOutputStream(Unknown Source)
        at javax.imageio.ImageIO.write(Unknown Source)
        at palapply.ImageIO.write(ImageIO.java:30)
        at gui.CommandInterpreter.convertFile(CommandInterpreter.java:164)
        at gui.BatchCommandInterpreter.convertFiles(BatchCommandInterpreter.java:151)
        at gui.BatchCommandInterpreter.convert(BatchCommandInterpreter.java:196)
        at gui.BatchUI.convert(BatchUI.java:270)
        at gui.BatchUI.buttonClicked(BatchUI.java:250)
        at BreezySwing.GBFrameButtonListener.actionPerformed(GBFrame.java:518)
        at javax.swing.AbstractButton.fireActionPerformed(Unknown Source)
        at javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source)
        at javax.swing.DefaultButtonModel.fireActionPerformed(Unknown Source)
        at javax.swing.DefaultButtonModel.setPressed(Unknown Source)
        at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(Unknown Source)
        at java.awt.Component.processMouseEvent(Unknown Source)
        at javax.swing.JComponent.processMouseEvent(Unknown Source)
        at java.awt.Component.processEvent(Unknown Source)
        at java.awt.Container.processEvent(Unknown Source)
        at java.awt.Component.dispatchEventImpl(Unknown Source)
        at java.awt.Container.dispatchEventImpl(Unknown Source)
        at java.awt.Component.dispatchEvent(Unknown Source)
        at java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source)
        at java.awt.LightweightDispatcher.processMouseEvent(Unknown Source)
        at java.awt.LightweightDispatcher.dispatchEvent(Unknown Source)
        at java.awt.Container.dispatchEventImpl(Unknown Source)
        at java.awt.Window.dispatchEventImpl(Unknown Source)
        at java.awt.Component.dispatchEvent(Unknown Source)
        at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
        at java.awt.EventQueue.access$500(Unknown Source)
        at java.awt.EventQueue$3.run(Unknown Source)
        at java.awt.EventQueue$3.run(Unknown Source)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
        at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
        at java.awt.EventQueue$4.run(Unknown Source)
        at java.awt.EventQueue$4.run(Unknown Source)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
        at java.awt.EventQueue.dispatchEvent(Unknown Source)
        at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
        at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
        at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
        at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
        at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
        at java.awt.EventDispatchThread.run(Unknown Source)
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
        at javax.imageio.ImageIO.write(Unknown Source)
        at palapply.ImageIO.write(ImageIO.java:30)
        at gui.CommandInterpreter.convertFile(CommandInterpreter.java:164)
        at gui.BatchCommandInterpreter.convertFiles(BatchCommandInterpreter.java:151)
        at gui.BatchCommandInterpreter.convert(BatchCommandInterpreter.java:196)
        at gui.BatchUI.convert(BatchUI.java:270)
        at gui.BatchUI.buttonClicked(BatchUI.java:250)
        at BreezySwing.GBFrameButtonListener.actionPerformed(GBFrame.java:518)
        at javax.swing.AbstractButton.fireActionPerformed(Unknown Source)
        at javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source)
        at javax.swing.DefaultButtonModel.fireActionPerformed(Unknown Source)
        at javax.swing.DefaultButtonModel.setPressed(Unknown Source)
        at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(Unknown Source)
        at java.awt.Component.processMouseEvent(Unknown Source)
        at javax.swing.JComponent.processMouseEvent(Unknown Source)
        at java.awt.Component.processEvent(Unknown Source)
        at java.awt.Container.processEvent(Unknown Source)
        at java.awt.Component.dispatchEventImpl(Unknown Source)
        at java.awt.Container.dispatchEventImpl(Unknown Source)
        at java.awt.Component.dispatchEvent(Unknown Source)
        at java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source)
        at java.awt.LightweightDispatcher.processMouseEvent(Unknown Source)
        at java.awt.LightweightDispatcher.dispatchEvent(Unknown Source)
        at java.awt.Container.dispatchEventImpl(Unknown Source)
        at java.awt.Window.dispatchEventImpl(Unknown Source)
        at java.awt.Component.dispatchEvent(Unknown Source)
        at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
        at java.awt.EventQueue.access$500(Unknown Source)
        at java.awt.EventQueue$3.run(Unknown Source)
        at java.awt.EventQueue$3.run(Unknown Source)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
        at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
        at java.awt.EventQueue$4.run(Unknown Source)
        at java.awt.EventQueue$4.run(Unknown Source)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
        at java.awt.EventQueue.dispatchEvent(Unknown Source)
        at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
        at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
        at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
        at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
        at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
        at java.awt.EventDispatchThread.run(Unknown Source)

I don't know why I've got a forbidden access to these images; moreover, the images are converted perfectly in PalApply 2.0.3 but only in png files with no problems in the log.
I updated Java script environment and I still got the same type of error.
PalApply 2.0.3 is excellent and does the job, but some games still use gif images and this version no longer support it...

bWWd:
Does anyone know of some gif editor that has similar feature built in
I don't know if you have solved this problem since?
 
My bad, I resolved the "Forbidden access" message by running PalApply 1.0 as administrator in Windows 10.
I don't have strangely this kind of problem with Palapply 2.0.3.
 
Added latest version to resources for download, made @Plombo owner, and associated with this discussion forum.

DC
 
anyone has commandline palapply 1 ? im writing gui for it

And i mean commandline version, the one with java gui aint it, wont accept custom paths in batch from commandline
I do remember that dinosaurs like me used commandline version of it long time ago in early obor days
 
Last edited:
Hey everyone. I rewrote my 10 year old program PalApply to support alpha masks and write well-optimized PNG output. I quietly released a replacement for the command line PalApply a year or two ago, but now I've gotten around to a full replacement for the GUI version that most people use.

Differences from the original PalApply, copied from the PalApply v2 readme:
  • If the source image has non-trivial alpha (partial transparency), then in addition to the usual indexed image, PalApply v2 will save a corresponding alpha mask that can be used with OpenBOR's alphamask command.
  • If the source image has any transparency at all, fully transparent pixels will be mapped to the transparent color (the first color in the palette).
  • The palette must be specified using an image file; there is no longer support for palettes in .pal/.act/.gpl format.
  • [since v2.0.1] The palette must be an image in PNG or GIF format or a palette in .act format; there is no longer support for palettes in .pal/.gpl format.
  • All output is in PNG format. GIF, PCX, and BMP are still supported as input formats, just not for output.
  • As a tradeoff for the above, the PNGs written by PalApply v2 are compressed to a small file size and optimized for fast loading. This is in sharp contrast to the poorly encoded PNGs written by the original PalApply, which were often larger than the equivalent GIFs.
  • The user interface of PalApply v2 is similar to that of its predecessor, but is more polished in various ways.
  • PalApply v2 is written in C rather than Java, so it doesn't require the Java runtime to be installed.

Everything else is about the same as the old PalApply; the interface is prettier but works the same. The only potentially contentious change is PalApply v2's inability to write GIF output. The only reason to use GIF over PNG is that GIFs load a bit faster, but the next release of OpenBOR will have my rewritten PNG decoder. With that, the optimized PNGs written by PalApply v2 load slightly faster than their GIF equivalents, so there will no longer be any reason to use GIF. If, in spite of all that, you still really want GIF output for whatever reason, you can still just use the original PalApply. It's not going anywhere.

With all that said, you can download PalApply v2 at the GitHub releases page. It supports Windows and Linux, but for Linux you'll have to compile it yourself.

I'm not aware of any issues with it, but it hasn't been tested as much as the original PalApply, so let me know if you find any issues.

Enjoy! ;D
Hello Plombo

Are you the creator of PalApply?

I need some help, essentially your software is critical for my work, but there's one thing that it does makes it hard to work with.
(I use gimp so i dunno what terminology other people use)

The problem is how the software deals with semi transparent pixels

PalApply currently takes semi transparent pixels and turns them into pixels.
I make animations with hundreds of frames
While we try our best to make sure there are no semi transparent pixels, the software (Spine or Live2D) sometimes forces it to happen and we can't do anything about it. Even adding a hard stroke around the image still turns up with some semi transparent pixels.
This ruins the images as the edges of images turn into a mess of colors

I guess the simple solution is if PalApply treats semi transparent pixels as nothing. I looked at your source code and it does seem to be capable with some tweaks. Is this something can be changed?

Thanks
 
Last edited:
PalApply currently takes semi transparent pixels and turns them into pixels.
That happens because you are working with 8bit images where there are no alpha, just a transparent color - RGB. 16 bit images are the ones where we have what you call semi transparent pixels : we have a 8bit color table + 8bit levels (255) of alpha - RGBA

You can easily bypass this if you use "save for web" in Photoshop, chosing 8bit and with no matter color
 
That happens because you are working with 8bit images where there are no alpha, just a transparent color - RGB. 16 bit images are the ones where we have what you call semi transparent pixels : we have a 8bit color table + 8bit levels (255) of alpha - RGBA

You can easily bypass this if you use "save for web" in Photoshop, chosing 8bit and with no matter color

Thanks for the suggestion, we tried to that just now.

Unfortunately, given how Spine/Live2D works, we need to cut up the image into many parts and layers.
We usually press it down to 8bit at the end, otherwise we would need to turn each layer into 8 bit while editing, which is way too much work (and lowers the quality of the image alot)
(below is an example of an image, and this is the simplest kind)

Each image set is at least 50 images so we can't do it manually after it is exported either. PalApply is critical to the workflow
1-1-ezgif.com-optimize.gif
 
The problem is how the software deals with semi transparent pixels

PalApply currently takes semi transparent pixels and turns them into pixels.
I make animations with hundreds of frames
While we try our best to make sure there are no semi transparent pixels, the software (Spine or Live2D) sometimes forces it to happen and we can't do anything about it. Even adding a hard stroke around the image still turns up with some semi transparent pixels.
This ruins the images as the edges of images turn into a mess of colors

I guess the simple solution is if PalApply treats semi transparent pixels as nothing. I looked at your source code and it does seem to be capable with some tweaks. Is this something can be changed?

I understand your problem, but it's not an accident that PalApply works this way. The output is like that to match how alpha masks work in OpenBOR, which can reproduce the original image's partial transparency by combining the regular output of PalApply with the alpha mask that PalApply generates for any image with partial transparency.

So although I can't change PalApply to fit your needs, I think there are a few decent ways that you can solve your problem:
  1. Make (or find) a batch tool that replaces any partial transparency beneath a certain threshold with full transparency. Run your images through it before running them through PalApply.
  2. Modify the source code of PalApply to do that itself, and use that custom version instead of the pre-compiled one.
  3. I don't know if you're using the output of PalApply with OpenBOR, but if you are, just use the alpha masks it generates with the "alphamask" command.
Sorry I can't be of more help!
 
Last edited:
I understand your problem, but it's not an accident that PalApply works this way. The output is like that to match how alpha masks work in OpenBOR, which can reproduce the original image's partial transparency by combining the regular output of PalApply with the alpha mask that PalApply generates for any image with partial transparency.

So although I can't change PalApply to fit your needs, I think there are a few decent ways that you can solve your problem:
  1. Make (or find) a batch tool that replaces any partial transparency beneath a certain threshold with full transparency. Run your images through it before running them through PalApply.
  2. Modify the source code of PalApply to do that itself, and use that custom version instead of the pre-compiled one.
  3. I don't know if you're using the output of PalApply with OpenBOR, but if you are, just use the alpha masks it generates with the "alphamask" command.
Sorry I can't be of more help!
Thanks for the reply

I just learned about the masking system in openbor. According to the manual it increases memory use. Does anyone know how much more it uses?

For example if my image is 100kb and the mask is 1kb is it just a 1% increase or is there more it this?
 
Thanks for the reply

I just learned about the masking system in openbor. According to the manual it increases memory use. Does anyone know how much more it uses?

For example if my image is 100kb and the mask is 1kb is it just a 1% increase or is there more it this?

IIRC it exactly doubles it, because the mask is a second bitmap in memory. That said, your 100kb image is not 100kb in the engine, because OpenBOR further optimizes and trims. It shaves off all unnecessary transparent area and removes the color table (768 bytes) from each image. Generally the bigger the image the more it can optimize, but mileage various of course.

No matter what, you'd be pretty hard pressed to put a dent in modern memory with images.

DC
 
Back
Top Bottom