Skip to content

Commit

Permalink
tmxrasterizer: Added --frames and --frame-duration arguments
Browse files Browse the repository at this point in the history
These allow exporting animated maps as multiple numbered images, which
can be combined into a GIF or other format using another tool.

The --advance-animations parameter stays for compatibility, and
determines the time of the first exported frame, whereas
--frame-duration determines the time between each frame.
  • Loading branch information
bjorn committed Jan 9, 2024
1 parent c462761 commit 5596096
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 10 deletions.
1 change: 1 addition & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

* JSON format: Fixed tile order when loading a tileset using the old format
* tmxrasterizer: Added --hide-object and --show-object arguments (by Lars Luz, #3819)
* tmxrasterizer: Added --frames and --frame-duration arguments to export animated maps as multiple images
* Windows: Fixed the support for WebP images (updated to Qt 6.5.3)

### Tiled 1.10.2 (4 August 2023)
Expand Down
32 changes: 28 additions & 4 deletions src/tmxrasterizer/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,15 +85,21 @@ int main(int argc, char *argv[])
QCoreApplication::translate("main", "Don't render object layers.") },
{ QStringLiteral("hide-image-layers"),
QCoreApplication::translate("main", "Don't render image layers.") },
{ QStringLiteral("advance-animations"),
QCoreApplication::translate("main", "If used, tile animations are advanced by the specified duration."),
QCoreApplication::translate("main", "duration") },
{ QStringLiteral("hide-object"),
QCoreApplication::translate("main", "Specifies an object to omit from the output image. Can be repeated to hide multiple objects. If multiple objects share the specified name they all will be hidden."),
QCoreApplication::translate("main", "name") },
{ QStringLiteral("show-object"),
QCoreApplication::translate("main", "If used only specified objects are shown. Can be repeated to show multiple specified objects only. If multiple objects share the specified name they all will be shown."),
QCoreApplication::translate("main", "name") }
QCoreApplication::translate("main", "name") },
{ QStringLiteral("advance-animations"),
QCoreApplication::translate("main", "If used, tile animations are advanced by the specified duration in milliseconds."),
QCoreApplication::translate("main", "duration") },
{ QStringLiteral("frames"),
QCoreApplication::translate("main", "Number of frames to export. This will add a frame number suffix to the image names. Animations are advanced by <frame-duration> for each frame."),
QCoreApplication::translate("main", "number") },
{ QStringLiteral("frame-duration"),
QCoreApplication::translate("main", "Duration of each frame in milliseconds, defaults to 100."),
QCoreApplication::translate("main", "number") },
});
parser.addPositionalArgument(QStringLiteral("map|world"), QCoreApplication::translate("main", "Map or world file to render."));
parser.addPositionalArgument(QStringLiteral("image"), QCoreApplication::translate("main", "Image file to output."));
Expand Down Expand Up @@ -157,5 +163,23 @@ int main(int argc, char *argv[])
}
}

if (parser.isSet(QLatin1String("frames"))) {
bool ok;
w.setFrameCount(parser.value(QLatin1String("frames")).toInt(&ok));
if (!ok || w.frameCount() < 0) {
qWarning().noquote() << QCoreApplication::translate("main", "Invalid number of frames specified: \"%1\"").arg(parser.value(QLatin1String("frames")));
exit(1);
}
}

if (parser.isSet(QLatin1String("frame-duration"))) {
bool ok;
w.setFrameDuration(parser.value(QLatin1String("frame-duration")).toInt(&ok));
if (!ok || w.frameDuration() < 0) {
qWarning().noquote() << QCoreApplication::translate("main", "Invalid frame-duration specified: \"%1\"").arg(parser.value(QLatin1String("frame-duration")));
exit(1);
}
}

return w.render(fileToOpen, fileToSave);
}
35 changes: 30 additions & 5 deletions src/tmxrasterizer/tmxrasterizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
#include "worldmanager.h"

#include <QDebug>
#include <QFileInfo>
#include <QImageWriter>

#include <memory>
Expand Down Expand Up @@ -131,12 +132,36 @@ bool TmxRasterizer::shouldDrawObject(const MapObject *object) const


int TmxRasterizer::render(const QString &fileName,
const QString &imageFileName)
QString imageFileName)
{
if (fileName.endsWith(QLatin1String(".world"), Qt::CaseInsensitive))
return renderWorld(fileName, imageFileName);
else
return renderMap(fileName, imageFileName);
const QFileInfo imageFileInfo(imageFileName);

const QString imagePath = imageFileInfo.path();
const QString imageBaseName = imageFileInfo.completeBaseName();
const QString imageSuffix = imageFileInfo.suffix();

const int frameCount = qMax(1, mFrameCount);

for (int frame = 0; frame < frameCount; ++frame) {
if (mFrameCount > 0) {
imageFileName = QString(QLatin1String("%1/%2%3.%4"))
.arg(imagePath, imageBaseName, QString::number(frame), imageSuffix);
}

int ret;

if (fileName.endsWith(QLatin1String(".world"), Qt::CaseInsensitive))
ret = renderWorld(fileName, imageFileName);
else
ret = renderMap(fileName, imageFileName);

if (ret)
return ret;

mAdvanceAnimations += mFrameDuration;
}

return 0;
}

int TmxRasterizer::renderMap(const QString &mapFileName,
Expand Down
8 changes: 7 additions & 1 deletion src/tmxrasterizer/tmxrasterizer.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ class TmxRasterizer
int tileSize() const { return mTileSize; }
int size() const { return mSize; }
int advanceAnimations() const { return mAdvanceAnimations; }
int frameCount() const { return mFrameCount; }
int frameDuration() const { return mFrameDuration; }
bool useAntiAliasing() const { return mUseAntiAliasing; }
bool smoothImages() const { return mSmoothImages; }
bool ignoreVisibility() const { return mIgnoreVisibility; }
Expand All @@ -57,6 +59,8 @@ class TmxRasterizer
void setTileSize(int tileSize) { mTileSize = tileSize; }
void setSize(int size) { mSize = size; }
void setAdvanceAnimations(int duration) { mAdvanceAnimations = duration; }
void setFrameCount(int frameCount) { mFrameCount = frameCount; }
void setFrameDuration(int frameDuration) { mFrameDuration = frameDuration; }
void setAntiAliasing(bool useAntiAliasing) { mUseAntiAliasing = useAntiAliasing; }
void setSmoothImages(bool smoothImages) { mSmoothImages = smoothImages; }
void setIgnoreVisibility(bool IgnoreVisibility) { mIgnoreVisibility = IgnoreVisibility; }
Expand All @@ -69,13 +73,15 @@ class TmxRasterizer

void setLayerTypeVisible(Layer::TypeFlag layerType, bool visible);

int render(const QString &fileName, const QString &imageFileName);
int render(const QString &fileName, QString imageFileName);

private:
qreal mScale = 1.0;
int mTileSize = 0;
int mSize = 0;
int mAdvanceAnimations = 0;
int mFrameCount = 0;
int mFrameDuration = 100;
bool mUseAntiAliasing = false;
bool mSmoothImages = true;
bool mIgnoreVisibility = false;
Expand Down

0 comments on commit 5596096

Please sign in to comment.