我正在寻找像QSprite这样的类,它负责从源文件中读取像素图,将源图像分割成图像序列并按索引返回子图像。
这样的事情:
class QSprite2
{
bool load(QUrl url, QSize frameSize);
QImage getFrame(int index);
};
有没有办法用现有的类来描述功能。或许我必须自己实现描述逻辑?
答案 0 :(得分:0)
您可以使用QQuickImageProvider
。这是我写的一个类似的东西:
SpriteImageProvider.h
:
#ifndef SPRITEIMAGEPROVIDER_H
#define SPRITEIMAGEPROVIDER_H
#include <QHash>
#include <QImage>
#include <QString>
#include <QQuickImageProvider>
#include "IsleGlobal.h"
class ISLE_EXPORT SpriteImageProvider : public QQuickImageProvider
{
public:
SpriteImageProvider();
QImage requestImage(const QString &id, QSize *size, const QSize &requestedSize) override;
private:
int parseFrameIndex(const QString &frameIndexStr) const;
int parseFrameWidth(const QString &frameWidthStr) const;
int parseFrameHeight(const QString &frameHeightStr) const;
QHash<QString, QImage> mImages;
};
#endif // SPRITEIMAGEPROVIDER_H
SpriteImageProvider.cpp
:
#include "SpriteImageProvider.h"
#include <QImage>
#include <QDebug>
SpriteImageProvider::SpriteImageProvider() :
QQuickImageProvider(QQmlImageProviderBase::Image)
{
}
static const QRgb whiteRgba = qRgba(255, 255, 255, 255);
static const QRgb magentaRgba = qRgba(255, 0, 255, 255);
static const QRgb transparentRgba = qRgba(0, 0, 0, 0);
QImage SpriteImageProvider::requestImage(const QString &id, QSize *size, const QSize &)
{
QStringList args = id.split(QLatin1String(","));
if (args.length() < 1) {
qWarning() << "Must pass at least the file name as arguments for SpriteImageProvider source";
return QImage();
} else if (args.length() != 1 && args.length() != 2 && args.length() != 4) {
qWarning() << "Must pass either (fileName), (fileName, frameIndex) or"
<< "(fileName, frameWidth, frameHeight, frameIndex) as arguments for SpriteImageProvider source";
return QImage();
}
const QString imageFilename = ":/" + args.first();
int frameIndex = -2;
int frameWidth = -2;
int frameHeight = -2;
if (args.length() > 1) {
frameIndex = parseFrameIndex(args.last());
if (frameIndex == -1)
return QImage();
}
if (args.length() == 4) {
frameWidth = parseFrameIndex(args.at(1));
if (frameWidth == -1)
return QImage();
frameHeight = parseFrameIndex(args.at(2));
if (frameHeight == -1)
return QImage();
}
QHash<QString, QImage>::const_iterator it = mImages.find(imageFilename);
if (it == mImages.end()) {
QImage image(imageFilename);
if (image.isNull()) {
qWarning() << "Failed to load image at" << imageFilename;
return image;
}
// TODO: is there a better way of doing this?
QImage alphaImage = image;
for (int y = 0; y < alphaImage.height(); ++y) {
for (int x = 0; x < alphaImage.width(); ++x) {
const QRgb pixelRgb = alphaImage.pixel(x, y);
if (pixelRgb == whiteRgba || pixelRgb == magentaRgba)
alphaImage.setPixel(x, y, transparentRgba);
}
}
mImages.insert(imageFilename, alphaImage);
it = mImages.find(imageFilename);
}
if (frameWidth == -2 || frameHeight == -2) {
if (frameIndex == -2) {
// Use the whole image.
frameWidth = it.value().width();
frameHeight = it.value().height();
frameIndex = 0;
} else {
frameWidth = 64;
frameHeight = 64;
}
}
// Copy an individual frame out of the larger image.
const int framesWide = it.value().width() / frameWidth;
const QRect subRect((frameIndex % framesWide) * frameWidth,
(frameIndex / framesWide) * frameHeight,
frameWidth,
frameHeight);
// qDebug() << "id" << id;
// qDebug() << "framesWide" << framesWide;
// qDebug() << "subRect" << subRect;
const QImage frameImage = it.value().copy(subRect);
*size = frameImage.size();
return frameImage;
}
int SpriteImageProvider::parseFrameIndex(const QString &frameIndexStr) const
{
bool convertedToIntSuccessfully = false;
const int frameIndex = frameIndexStr.toInt(&convertedToIntSuccessfully);
if (!convertedToIntSuccessfully) {
qWarning() << "Failed to convert frame index" << frameIndexStr << "to an int";
return -1;
}
return frameIndex;
}
int SpriteImageProvider::parseFrameWidth(const QString &frameWidthStr) const
{
bool convertedToIntSuccessfully = false;
const int frameWidth = frameWidthStr.toInt(&convertedToIntSuccessfully);
if (!convertedToIntSuccessfully) {
qWarning() << "Failed to convert frame width" << frameWidthStr << "to an int";
return -1;
}
return frameWidth;
}
int SpriteImageProvider::parseFrameHeight(const QString &frameHeightStr) const
{
bool convertedToIntSuccessfully = false;
const int frameHeight = frameHeightStr.toInt(&convertedToIntSuccessfully);
if (!convertedToIntSuccessfully) {
qWarning() << "Failed to convert frame height" << frameHeightStr << "to an int";
return -1;
}
return frameHeight;
}
它还支持“alpha键” - 源图像中的白色和品红色像素将变为透明像素。
它已在QML引擎中注册,如下所示:
mEngine->addImageProvider("sprite", new SpriteImageProvider);
并在QML中使用:
import QtQuick 2.5
Image {
source: qsTr('image://sprite/sprites/hugh.png,%1').arg(_sceneItemComponent ? _sceneItemComponent.facingDirection : 0)
}
其中facingDirection
是要使用的帧索引。您还可以传递其他参数,这些参数在.cpp文件中提到。