Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > С/С++: Кроссплатформенное программирование, Qt/Gtk+/wxWidgets > Сохранение QGLWidget


Автор: math64 4.9.2015, 12:51
пробую сохранить так
Код

    QImage image = glWidget->grabFrameBuffer();
    image.save(fileName);

или так
Код

    QPixmap pixmap = glWidget->renderPixmap();
    pixmap.save(fileName);

в обоих случаях программа вылетает. Не могу понять почему.
(рисуется кубик из примера Textures)

Автор: Amp 4.9.2015, 18:03
Из какого места вызываешь? 

Автор: math64 4.9.2015, 22:14
Из слота  saveAction, после получения имени файла через QFileDialog.
Ну и в примерах texture и grabber есть анимация - у меня её нет.

Автор: math64 7.9.2015, 08:15
Вот так:
Код

void MainWindow::on_actionSave_triggered()
{
    //QImage image = glWidget->grabFrameBuffer();
    //qDebug() << image.size();

    QPixmap pixmap = glWidget->renderPixmap();
    qDebug() << pixmap.size();

    QString fileName =
            QFileDialog::getSaveFileName(this,
                                         "Save Image", ".", "Image(*.png *.jpg *.jpeg *.bmp)");
    if (fileName.isEmpty())
        return;
    qDebug() << fileName;

    //image.save(fileName);
    pixmap.save(fileName);
}

GLWidget.cpp:
Код

#include "glwidget.h"

#include <QtOpenGL>

#include <math.h>

GLWidget::GLWidget(QWidget *parent) :
    QGLWidget(parent)
{
    xRot = 0;
    yRot = 0;
    zRot = 0;
}

GLWidget::~GLWidget()
{

}

QSize GLWidget::minimumSizeHint() const
{
    return QSize(50, 50);
}

QSize GLWidget::sizeHint() const
{
    return QSize(400, 400);
}

static void qNormalizeAngle(int &angle)
{
    while (angle < 0)
        angle += 360 * 16;
    while (angle > 360 * 16)
        angle -= 360 * 16;
}

void GLWidget::setXRotation(int angle)
{
    qNormalizeAngle(angle);
    if (angle != xRot) {
        xRot = angle;
        emit xRotationChanged(angle);
        updateGL();
    }
}

void GLWidget::setYRotation(int angle)
{
    qNormalizeAngle(angle);
    if (angle != yRot) {
        yRot = angle;
        emit yRotationChanged(angle);
        updateGL();
    }
}

void GLWidget::setZRotation(int angle)
{
    qNormalizeAngle(angle);
    if (angle != zRot) {
        zRot = angle;
        emit zRotationChanged(angle);
        updateGL();
    }
}

void GLWidget::initializeGL()
{
    makeObject();

    qglClearColor(Qt::lightGray);

    glEnable(GL_DEPTH_TEST);
    glEnable(GL_CULL_FACE);
    glEnable(GL_TEXTURE_2D);

    glEnable(GL_DEPTH_TEST);
    glEnable(GL_NORMALIZE);
}

void GLWidget::paintGL()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();
    glTranslatef(0.0, 0.0, -10.0);
    glRotatef(xRot / 16.0, 1.0, 0.0, 0.0);
    glRotatef(yRot / 16.0, 0.0, 1.0, 0.0);
    glRotatef(zRot / 16.0, 0.0, 0.0, 1.0);

    glVertexPointer(3, GL_FLOAT, 0, vertices.constData());
    glTexCoordPointer(2, GL_FLOAT, 0, texCoords.constData());
    glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);

    for (int i = 0; i < 6; ++i) {
        glBindTexture(GL_TEXTURE_2D, textures[i]);
        glDrawArrays(GL_TRIANGLE_FAN, i * 4, 4);
    }
}

void GLWidget::resizeGL(int width, int height)
{
    int side = qMin(width, height);
    glViewport((width - side) / 2, (height - side) / 2, side, side);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(-0.5, +0.5, -0.5, +0.5, 4.0, 15.0);
    glMatrixMode(GL_MODELVIEW);
}

void GLWidget::mousePressEvent(QMouseEvent *event)
{
    lastPos = event->pos();
}

void GLWidget::mouseMoveEvent(QMouseEvent *event)
{
    int dx = event->x() - lastPos.x();
    int dy = event->y() - lastPos.y();

    if (event->buttons() & Qt::LeftButton) {
        setXRotation(xRot + 8 * dy);
        setYRotation(yRot + 8 * dx);
    } else if (event->buttons() & Qt::RightButton) {
        setXRotation(xRot + 8 * dy);
        setZRotation(zRot + 8 * dx);
    }
    lastPos = event->pos();
}

void GLWidget::makeObject()
{
    static const int coords[6][4][3] = {
        { { +1, -1, -1 }, { -1, -1, -1 }, { -1, +1, -1 }, { +1, +1, -1 } },
        { { +1, +1, -1 }, { -1, +1, -1 }, { -1, +1, +1 }, { +1, +1, +1 } },
        { { +1, -1, +1 }, { +1, -1, -1 }, { +1, +1, -1 }, { +1, +1, +1 } },
        { { -1, -1, -1 }, { -1, -1, +1 }, { -1, +1, +1 }, { -1, +1, -1 } },
        { { +1, -1, +1 }, { -1, -1, +1 }, { -1, -1, -1 }, { +1, -1, -1 } },
        { { -1, -1, +1 }, { +1, -1, +1 }, { +1, +1, +1 }, { -1, +1, +1 } }
    };

    for (int j=0; j < 6; ++j) {
        textures[j] = bindTexture
            (QPixmap(QString(":/res/side%1.png").arg(j + 1)), GL_TEXTURE_2D);
    }

    for (int i = 0; i < 6; ++i) {
        for (int j = 0; j < 4; ++j) {
            texCoords.append
                (QVector2D(j == 0 || j == 3, j == 0 || j == 1));
            vertices.append
                (QVector3D(0.2 * coords[i][j][0], 0.2 * coords[i][j][1],
                           0.2 * coords[i][j][2]));
        }
    }
}

Автор: Amp 8.9.2015, 13:06
Посмотри отладчиком в каком именно месте падает. Надеюсь исходники Qt стоят?
Хоть у тебя падет и там и там, но вместо renderPixmap надежнее использовать grabFrameBuffer, т.к. последний сводится фактически к вызову glReadPixels. А renderPixmap будет повторно вызывать initializeGL(), что в твоем случае возможно и приводит к некоторым проблемам. Например пересозданию текстур, заполнению texCoords и vertices без предварительной очистки.

Автор: math64 9.9.2015, 09:21
В Windows у меня отладчик не работает - не знаю почему, когда в первый раз ставил Qt, работал.
В Linux валится на d->glcx->doneCurrent(); в QPixmap QGLWidget::renderPixmap(int w, int h, bool useContext)
или на
d->glcx->makeCurrent(); в void QGLWidget::makeCurrent() из QImage QGLWidget::grabFrameBuffer(bool withAlpha)
при этом на консоль валится
can't find linker symbol for virtual table for `QGLWidget' value
  found `QGLContext::bindTexture(QString const&)' instead

Автор: math64 9.9.2015, 15:19
Была глупая ошибка.
в MainWindow::MainWindow(QWidget *parent)
вместо
Код

    glWidget = new GLWidget(this);
    setCentralWidget(glWidget);

было
Код

    GLWidget* glWidget = new GLWidget(this);
    setCentralWidget(glWidget);


Автор: math64 10.9.2015, 16:06
Дополнительно: Как сохранить с прозрачным фоном?

Автор: Amp 10.9.2015, 16:32
Последний аргумент glClearColor должен быть 0, и grabFrameBuffer(true)

Автор: math64 11.9.2015, 08:30
Не получается. На всякий случай проверяю на наличие прозрачных пикселей:
Код

void GLWidget::paintGL()
{
    glClearColor(0.75, 0.75, 0.75, 0);
    ...
}

void MainWindow::on_actionSave_triggered()
{
    ...
    QImage image = glWidget->grabFrameBuffer(true);
    QSize size = image.size();
    int w = size.width();
    int h = size.height();
    bool alpha = false;
    for(int y = 0; y < h; y++) {
        QRgb* s = (QRgb*)image.scanLine(y);
        for(int x = 0; x < w; x++) {
            QRgb rgb = s[x];
            if (qAlpha(rgb) != 0xFF) {
                s[x] = 0;
                alpha = true;
            }
        }
    }
    qDebug() << size << alpha;
    ...
}

QSize(209, 224) false

Автор: Amp 11.9.2015, 12:37
Приложи лучше минимальный проект.

Автор: math64 11.9.2015, 13:29
В конструкторе нужно добавить формат QGL::AlphaChannel:
Код

GLWidget::GLWidget(QWidget *parent) :
    QGLWidget(QGLFormat(QGL::AlphaChannel), parent)
{
...
}

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)