Command line application for converting SWF files to PDF or SVG. This program differs from existing alternatives by the fact that it's explicitly meant to convert back files that were originally in PDF (or other vector formats) and have been converted to SWF using programs such as swf-tools' pdf2swf or Adobe InDesign.
As such, only a subset of the SWF specification is supported, with no support for animations. See limitations for more details. Only static files can be converted. For example, this program could be be used to convert a book composed of one SWF file per page.
To reduce output file size, several features are available:
- Merging similar fonts across files.
- Downsampling images to limit density.
- Detecting and removing duplicate images.
- Using JPG format only, even for images with alpha channel.
- Rasterizing frames with complex paths (PDF only).
- Reusing identical paths (SVG only).
- Compressing output.
The latest release can be found under the Releases section. Java 8 or later is required to run this program. The same build should be able to run on all desktop platforms.
The JAR file can be run using the following command:
java -jar swf-convert.jar [main options] <output format> <input files> [output options]
It can also take a configuration file:
java -jar swf-convert.jar @config.txt
Multiple input files or folders can be specified. A file collection is created for each file or folder specified. Some arguments will require to have the same number of arguments as there are input collections.
It is recommended to use -Xmx
to increase heap size when converting large input collections (>1000 files) since
the program uses a lot of memory, particularly for PDF frame rasterization. As much as 10 GB has been required in my
case...
For use in place of [main options]
in the above command.
-h
,--help
: Show help message for the program.-v
,--version
: Show version name.--log <level>
: Set minimum log level to show in stdout (off: 0, fatal: 1, error: 2, warn: 3, info: 4, debug: 5, all: 6). Logs of all levels are also written to~/swfconvert/logs
.-s
,--silent
: Don't display progress during conversion.
For use in place of [output options]
in the above command. Shared by all output formats.
-h
,--help
: Show help message for the output format.-o
,--output <path> [paths]
: Output files or directories. There must be as many as input file collections. By default, output is written to the same path as input. If specifying files, they must have the same extension as the desired output format.-t
,--tempdir <path>
: Temp directory used for intermediate files. Default temp directory is the same as input directory. Temp files are automatically removed after conversion, unless specified otherwise.-e
,--ignore-empty
: Ignore empty frames, not generating output for them.
-g
,--dont-group-fonts
: Used to disable font grouping (merging compatible fonts in a single font).--keep-font-names
: Used to keep original font names instead of using generic names.
--keep-duplicate-images
: Used to keep duplicate images with same binary data.--image-format <format>
: Format to use for images, can be one ofdefault
,jpg
orpng
. Default isdefault
, in which case PNG format will be used for DefineBitsLossless tags and JPEG format will be used for DefineBitsJPEG tags. tags.--jpeg-quality <quality>
: JPEG image quality between 0 and 100. Default is 75.
--downsample-images
: Used to downsample images to limit output density.--downsample-filter <name>
: Filter used to downsample images, can be one offast
,bell
,bicubic
,bicubichf
,box
,bspline
,hermite
,lanczos3
,mitchell
ortriangle
. Default islanczos3
.--downsample-min-size <size>
: Minimum size in pixels that images can be downsampled to or from. Must be at least 3 px, default is 10 px.--max-dpi <dpi>
: If downsampling images, the maximum allowed image density. Default is 200 DPI.
For use in place of [output options]
in the above command, with the pdf
output format.
PDF output will produce one page per frame. The frames of all files in a collection are written to the same output file.
--no-compress
: Used to disable output PDF compression.--metadata <file> [files]
: Metadata JSON files used for each input file collection. Use underscore_
to apply no metadata for a particular collection. There must be as many values as there are input collections. See this section for more information on JSON schema.--dont-optimize-page-labels
: Used to disable page labels optimization (if set in metadata).
--rasterization-enabled
: Used to enable rasterization of complex frames.--rasterization-threshold <threshold>
: Minimum input file complexity required to perform rasterization, in (somewhat) arbitrary units. Default is 100,000. Should be tuned manually to see which at which point rasterization produces smaller files.--rasterization-dpi <dpi>
: Density in DPI to use to rasterize frames if rasterization is enabled. Default is 200 DPI.--rasterization-format
: Image format to use for rasterized frames, eitherjpg
orpng
. Default isjpg
.--rasterization-jpeg-quality
: JPEG image quality for rasterization, between 0 and 100. Default is 75.
For use in place of [output options]
in the above command, with the svg
output format.
SVG will produce one file per input frame.
-p
,--pretty
: Used to pretty print output SVG. This also disables a number of optimizations to increase readability.--svgz
: Used to output in SVGZ format (gzip compression).--no-prolog
: Used to omit the XML prolog.--precision
: Precision of SVG path, position, and dimension values. Default is 1.--transform-precision
: Precision of SVG transform values. Default is 2.--percent-precision
: Precision of SVG percentage values. Default is 2.--images-mode <mode>
: Controls how images are included in SVG, can one ofexternal
(as files) orbase64
(embedded as base64 encoded URLs). Default isexternal
.--fonts-mode <mode>
: Controls how fonts are included in SVG, can be one ofexternal
(as TTF files),base64
(embedded as base64 encoded URLs) ornone
(no fonts, use paths).
When images and fonts are not embedded, the files are placed in the same directory as the output.
For use in place of [output options]
in the above command, with the ir
output format.
IR will produce one JSON file per input frame.
When converting SWF to the chosen output format, the program first converts the SWF toa SVG-like intermediate representation in order to abstract the difficulties presented by the SWF format. For debugging purposes, it's possible to output this IR as JSON structures. Images and fonts are written as files.
-p
,--pretty
: Used to pretty print output JSON.--indent-size <size>
: Indent size used if pretty printing.--y-direction
: Y axis direction, eitherup
ordown
. Default is up.
For use in place of [output options]
in the above command.
-DkeepFonts
,-DkeepImages
: used to keep temp image and font files.- Parallelization options to control which steps are run in parallel. Useful when debugging.
-DparallelSwfDecoding
: SWF file decoding.-DparallelSwfConversion
: conversion to intermediate representation.-DparallelImageCreation
: creation of image files.-DparallelFrameRendering
: rendering from IR to output format.
- Draw bounds to draw rectangles around SWF element bounds for debugging:
-DdrawShapeBounds
: for DefineShape tags.-DdrawTextBounds
: for DefineText tags.-DdrawClipBounds
: for PlaceObject tags with clipping depth.-DdebugLineWidth=<width>
: bounds line width in twips, default is 20 twips.-DdebugLineColor=<color>
: bounds line color, default is green. (color is a#rrggbb
or#aarrggbb
hex color)
- Features disable for debugging:
-DdisableClipping
: disable clipping.-DdisableBlending
: disable blending except alpha blend mode.-DdisableMasking
: disable alpha blend mode.
-DframePadding
: padding to add around frames in inches.- Custom font scale values, thoroughly explained here. Value is a list of 4 comma-separated values
enclosed in brackets.
-DfontScale2=[<sx>,<sy>,<usx>,<usy>]
: for DefineFont2 tags.-DfontScale3=[<sx>,<sy>,<usx>,<usy>]
: for DefineFont3 tags.
-DframeSize=[<width>,<height>]
: if set, overrides frame size defined in SWF, for all frames. Dimensions are in inches.-DbitmapMatrixOffset
: additional offset to use for bitmap fill matrix on shape tags. Default is [0, 0].-DignoreGlyphOffsetsThreshold=<threshold>
: threshold under which custom glyph advances are ignore for DefineText tags, in glyph space units (1 em = 1024 glyph space units). Used to reduce output file size. Default is 32.-DrecursiveFrames
: if set, frames contained in sprites become top-level frames, recursively. Otherwise, only top-level frames are used (default).
Keep in mind that these options are meant for advanced use or for debugging purposes. Otherwise common uses include:
-DignoreGlyphOffsetsThreshold=0
: keep all original glyph advances.-DfontScale2=[0.05, 0.05, 20, -20]
: font scale used for converting files made with swf-tools.-DkeepFonts
and-DkeepImages
: extracting fonts or images.
1. PDF to SWF and back.
Here an arbitrary PDF with 92 pages is converted to SWF files with swf-tools' pdf2swf:
pdf2swf -o pages/%.swf -z input.pdf
The result is 92 SWF files named 1.swf to 92.swf in the pages
directory.
Now let's convert them back to a single PDF file using swf-convert:
java -jar swfconvert.jar pdf pages/ -o report.pdf
--image-format jpg --ignore-empty
-DfontScale2=[0.05,0.05,20,-20]
Additionally we'll ignore empty frames, use only JPG images, and we'll use the special font scale option needed
for swf-tools. In a few seconds, the report.pdf
file is created. 40 fonts were created out of the 719 contained in all
input files, and 333 duplicate images were removed out of 344 images!
2. Self-contained SVG
A SWF file with a single frame is converted to a SVG:
java -jar swfconvert.jar --log 4
svg input.swf -o output.svg
--downsample-images --max-dpi 30 --image-format jpg
--images-mode base64 --fonts-mode none
--transform-precision 2 --no-prolog
Images are embedded and paths are used instead of fonts. Precision for the transform
attribute is also increased to
avoid rounding issues with fonts-mode none
. To avoid making the SVG too big, images are also downsampled.
swf-convert can only convert static files, with no support for animations or actions. Most other limitations arise from the fact that I had no test data to test some features with, so I opted for a lazy implementation. Here's a detailed list of current limitations.
- Tags:
- Supported tags: ShowFrame, DefineShape, PlaceObject, RemoveObject, DefineBitsLossless, DefineBitsJPEG2, DefineShape2, PlaceObject2, RemoveObject2, DefineShape3, DefineText2, DefineBitsJPEG3, DefineBitsLossless2, DefineSprite, DefineFont2, PlaceObject3, DefineFont3, DefineShape4.
- All other tags are unsupported.
- Shapes:
- Radial gradient fill.
- Tiled or smoothed bitmap fill. (only bitmap fill type 0x41 is supported)
- Non-solid line fill style.
- Different start and end line caps.
- Reflect & repeat gradient spread mode.
- Linear RGB mode gradient interpolation
- Fonts & text:
- Font kernings.
- Text spans using both DefineFont2 and DefineFont3 fonts within the same DefineText object.
- DefineFont/DefineFont4 as mentioned previously.
- Display list:
- PlaceObject tags with PlaceFlagMove set to 1.
- Placing a character at a depth where another already resides.
- Interlaced clip paths.
- All filters except identity color matrix.
- Non-image mask (alpha blend mode).
Nearly all of these limitations will result in an exception being thrown, and the conversion will fail. If you ever have an use case needing support for one of the above, please open an issue and provide the required test data, I'll do my best to implement it. Again, this tool was implemented lazily as to cover my own use case and nothing more. More test data will surely allow to fill the holes.
When I say test data, I mean SWF files that can be converted and the result is visually compared with the original. I unfortunately didn't spend the time implementing automated testing that would do that.
- Unsupported blend modes: add, difference, erase, invert, null, subtract.
- Unsupported blend modes: add, erase, invert, null, subtract.
- Blending will not work if blending against a background that was clipped. This is due to SVG creating isolated groups after clipping, meaning the background is reset to transparent black.
- SVG produced is often incompatible with a lot of viewers, only Chrome seems to have full support.
- Please note that SVG is a bit of a second-class citizen in this project since many tools already exist to do the same job. But it should still work fine for most purposes.
The project is built with Gradle, which can be run with:
./gradlew <tasks> [options]
Useful tasks are:
clean
: clean build resultsbuild
: build projectdetekt
: run detekt analysis on projectapp:dist
: output fat jar toapp/build/libs
app:run
: run program, using properties fromdev.properties
file:app-test-working-dir
: working dir to useapp-test-args
: options to use
All contributions are welcome. Please read contribution guidelines.
View the CHANGELOG.md
file for detailed release notes.
This program is licensed under LGPL v3, see the license file for more details. It uses modified code
for the following libraries, which can be found in the libsrc
directory:
- DoubleType: for creating TTF font files - GPL v2
- transform-swf: for decoding SWF files - BSD 3-clause
Other libraries are also used:
- Apache PDFBox: for creating PDF files - Apache 2.0
- Dagger: dependency injection - Apache 2.0
- JCommander: CLI - Apache 2.0
- Java image scaling: for downsampling images - BSD 3-clause
- log4j2: logging - Apache 2.0