Russian Qt Forum
Ноябрь 22, 2024, 22:06 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: QImage: out of memory, returning null image  (Прочитано 11535 раз)
nozog
Гость
« : Ноябрь 25, 2009, 11:44 »

Здравствуйте.

Создал класс занимающийся увеличением картинки.
Вызывая много раз подряд слот zoomIn() руками через сигнал pushbutton Clicked (не в цикле)
происходит следующее:
  изображение увеличивается до определенного значения коэффициента масштабирования(zoom_value),
  далее выводится сообщение: "QImage: out of memory, returning null image" при попытке
  увеличить исходное изображение на предыдущее значение коэффициента масштабирования(zoom_value)
  сообщение повторяется пока коэффициент масштабирования не станет равен 1/zoom_value

Задача была создать слот с логигой:
  увеличить изображение
  если невозможно то вернуть предыдущее увеличение

Пожалуйста подскажите что не так сделал и в чем ошибка,
почему после "QImage: out of memory, returning null image"
увеличивая на предыдуший коэффициент сново
выводится "QImage: out of memory, returning null image"

Спасибо
=====================================
Вот класс
=====================================
Код:
class Viewer : public QWidget{
...
public slots:
void zoomIn();
protected:
QImage *image;
QImage *t_image;
QPainter painter;
void paintEvent(QPaintEvent * event);
qreal zoom_value; // коэф. масштабирования
};
--------------------------------
Viewer::Viewer(QWidget *parent) : QWidget(parent){
zoom_value = 1.0;
image = new QImage();
t_image = new QImage();
if(image->load("...jpg")){
t_image->operator = (*image);
if(!t_image->isNull()){
setGeometry(QRect(0,0,t_image->width(),t_image->height()));
}
}
}
void Viewer::paintEvent(QPaintEvent *event){
qDebug()<<"paint:";
if(!t_image->isNull()){
qDebug()<<" draw image";
painter.begin(this);
painter.drawImage(0,0,*t_image);
painter.end();
}
else
qDebug()<<" image is null";
}
void Viewer::zoomIn(){
if(!t_image->isNull()){
QMatrix matrix;
zoom_value*=1.3;
t_image->operator = (image->transformed(matrix.scale(zoom_value,zoom_value)));
while(t_image->isNull()){
zoom_value/=1.3;
qDebug()<<" image is null, zoom value = "<<zoom_value;
t_image->operator =(image->transformed(matrix.scale(zoom_value,zoom_value)));
}
qDebug()<<"transform image["<<image->size()<<"] to ["<<t_image->size()<<"]";
qDebug()<<" image is OK,  zoom value = "<<zoom_value;
setGeometry(QRect(0,0,t_image->width(),t_image->height()));
update();
}
}
=====================================
вот лог с коментариями
=====================================
Код:
transform image[ QSize(800, 600) ] to [ QSize(1040, 780) ] 
 image is OK,  zoom value =  1.3
paint:
 draw image
// изображение увеличелось

...

transform image[ QSize(800, 600) ] to [ QSize(11029, 8272) ]
 image is OK,  zoom value =  13.7858
paint:
 draw image
// изображение увеличелось
QImage: out of memory, returning null image
 image is null, zoom value =  13.7858

...

QImage: out of memory, returning null image
 image is null, zoom value =  0.0725382
transform image[ QSize(800, 600) ] to [ QSize(14337, 10753) ]
 image is OK,  zoom value =  0.0725382
paint:
 draw image
// изображение увеличелось!!!

transform image[ QSize(800, 600) ] to [ QSize(75, 57) ]
 image is OK,  zoom value =  0.0942996
paint:
 draw image
// изображение уменьшилось от исходного в zoom value =  0.0942996 раз
 
transform image[ QSize(800, 600) ] to [ QSize(98, 74) ]
 image is OK,  zoom value =  0.122589
paint:
 draw image
// изображение увеличелось
итд
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #1 : Ноябрь 25, 2009, 16:23 »

Код:
t_image->operator = (*image);
...
t_image->operator =(image->transformed(matrix.scale(zoom_value,zoom_value)));
Зачем такие выкрутасы? Почему не
Код:
*t_image = *image;
...
*t_image = image->transformed(matrix.scale(zoom_value,zoom_value);
?

А главное

Цитировать
QImage & QImage::operator= ( const QImage & image )

Assigns a shallow copy of the given image to this image and returns a reference to this image.
А это значит что оба t_image и image будут ссылаться на те же данные. Поэтому

Код:
*t_image = image->copy();  // если уж хочется скопировать, хотя не видно зачем
...
*t_image = image->transformed(matrix.scale(zoom_value,zoom_value);

Записан
nozog
Гость
« Ответ #2 : Ноябрь 26, 2009, 14:57 »


Код:
t_image->operator = (*image);
...
t_image->operator =(image->transformed(matrix.scale(zoom_value,zoom_value)));
Зачем такие выкрутасы? Почему не
Код:
*t_image = *image;
...
*t_image = image->transformed(matrix.scale(zoom_value,zoom_value);
?

Согласен но не суть.

А главное

Цитировать
QImage & QImage::operator= ( const QImage & image )

Assigns a shallow copy of the given image to this image and returns a reference to this image.
А это значит что оба t_image и image будут ссылаться на те же данные. Поэтому

Код:
*t_image = image->copy();  // если уж хочется скопировать, хотя не видно зачем
...
*t_image = image->transformed(matrix.scale(zoom_value,zoom_value);

результат тотже

хотел сделать zoom в painEvent что то типа:

Код:
 painter.begin(this);
 painter.scale(zoom_value,zoom_value)
 painter.drawImage(0,0,*t_image);
 painter.end();

но подумал что это долго для больших изображений
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #3 : Ноябрь 26, 2009, 17:50 »

У меня впечатление что если Ваш текст "причесать", то он и будет работать как надо. Выкладывайте компилябельный проект, попробуем
Записан
nozog
Гость
« Ответ #4 : Ноябрь 27, 2009, 14:41 »

У меня впечатление что если Ваш текст "причесать", то он и будет работать как надо. Выкладывайте компилябельный проект, попробуем

Выделил в отдельный проект
Пожалуйста, пробуйте,
только имя исходного изображения измените.

Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #5 : Ноябрь 27, 2009, 18:12 »

Выделил в отдельный проект
Пожалуйста, пробуйте,
только имя исходного изображения измените.
Подрихтовал под свой вкус, поставил ограничители на zoom (attachment). Работает нормально, памяти ест сколько положено. Проблема о которой Вы говорили - да, видел, но исчезла сразу как только я убрал член класса QPainter (использовать др. painter кроме стекового = верный путь к неприятностям).
Записан
nozog
Гость
« Ответ #6 : Ноябрь 27, 2009, 21:32 »

спасибо, в понедельник посмотрю
Записан
nozog
Гость
« Ответ #7 : Ноябрь 30, 2009, 10:36 »

Igors, возникло несколько вопросов:
1.
использовать др. painter кроме стекового = верный путь к неприятностям
можно по подробнее почему именно так
2. почему QImage image а не QImage *image с выделение памяти в конструкторе
3. зачем ограничение в 1Gb
4. если t_image.isNull() то должно остаться предыдущее значение, а не исходное,
   тогда:   
Код:
	if (t_image.isNull()){
zoom_value = 1.0;
qDebug() << " image is null, zoom value = " << zoom_value;
t_image = image;
}
else {
CODE
}

        переходит в что-то типа:
Код:
	if(t_image.isNull()){
zoom_value/=1.3;
qDebug()<<" image is null, zoom value = "<<zoom_value;
t_image = image.transformed(matrix.scale(zoom_value, zoom_value));
}
//else {
CODE
//}
       
        и далее в   
Код:
	while(t_image.isNull()){
zoom_value/=1.3;
qDebug()<<" image is null, zoom value = "<<zoom_value;
t_image = image.transformed(matrix.scale(zoom_value, zoom_value));
}
//else {
CODE
//}
   так как при этом возвращается исходная проблема   
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #8 : Ноябрь 30, 2009, 11:34 »

Igors, возникло несколько вопросов:
1.
использовать др. painter кроме стекового = верный путь к неприятностям
можно по подробнее почему именно так
2. почему QImage image а не QImage *image с выделение памяти в конструкторе
3. зачем ограничение в 1Gb
4. если t_image.isNull() то должно остаться предыдущее значение, а не исходное,
   тогда:   
1) Не могу объяснить "строго научно/теоретически" но на практике рисование всегда начинается с нуля и заканчивается полным освобождением задействованных ресурсов. В том же Вындоуз - начали рисовать, взяли контекст GetClientDC(), отрисовали, освободили ReleaseDC(). Можно хранить атрибуты (браши, цвета и.т.п) но никак не контекст. При каждом новом рисовании все атрибуты заряжаются в контекст с нуля. Как показала жизнь - остальное не работает.

2) Можно конечно и указатель но член-объект в данном случае  естественнее. Вы собираетесь обыгрывать ситуацию когда t_image = 0? Нет и не предвидится, этот член класса всегда существует. Зачем тогда все время приклеивать к  указателю звездочку?

3) По крайней мере не все ОС могут выделять блок памяти больше 1 Gb (даже если она есть физически), поэтому незачем нарываться на отказ памяти. Заметим что для рисования еще раз потребуется такой же блок.

4) Не делите на 1.3 а запоминайте предыдущий zoom и используйте его. Дело темное что произойдет после отказа памяти и все ли Qt корректно восстановит. Лучше "начать от печки" если это случилось
Записан
nozog
Гость
« Ответ #9 : Декабрь 01, 2009, 10:55 »

Вышел из ситуации так:

Код:
void Widget::paintEvent ( QPaintEvent * event )  {
...
painter.drawImage(QRect(0,0,width(),height()),image);
...
}

Все как и хотел, даже второй QImage не понадобился,добавил вращение.
Проявился такой эффект:
Если изображение меньше виджета то
при вращении на +- 90 все нормально,
при +- 180 картинка прилепает в левый верхний угол;
скорее всего ошибка у меня но что-то никак не могу найти,
может глянете в продолжение беседы ?
Спасибо.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #10 : Декабрь 01, 2009, 13:57 »

Вышел из ситуации так:

Код:
void Widget::paintEvent ( QPaintEvent * event )  {
...
painter.drawImage(QRect(0,0,width(),height()),image);
...
}

Все как и хотел, даже второй QImage не понадобился,добавил вращение.
Проявился такой эффект:
Если изображение меньше виджета то
при вращении на +- 90 все нормально,
при +- 180 картинка прилепает в левый верхний угол;
скорее всего ошибка у меня но что-то никак не могу найти,
может глянете в продолжение беседы ?
Спасибо.
Смотрим: QPainter член класса. Вызов painter.end() отсутствует. Под вращением понимаются повороты на 90/180 градусов каждый из которых обрабатывается отдельно. Хмм... И кто Вам сказал что угол может быть только до 360? Улыбающийся Как Вы написали, так оно и будет работать. Пишите аккуратно и старательно - и все получится.
Записан
nozog
Гость
« Ответ #11 : Декабрь 02, 2009, 11:14 »

Смотрим: QPainter член класса. Вызов painter.end() отсутствует.
согласен, забыл.

Под вращением понимаются повороты на 90/180 градусов каждый из которых обрабатывается отдельно.Хмм...
можно все вместе обаботать,но это дело вкуса и опыта

И кто Вам сказал что угол может быть только до 360? Улыбающийся
нужно вращение только на угол кратный 90 + приведение угла в методе fitRotate() из чего и следует
 утверждение о возможных значениях углов.

Как Вы написали, так оно и будет работать. Пишите аккуратно и старательно - и все получится.
Истина. В методе fitRotate()  заменил setGeometry() на resize() прыжки в левый верхний угол прекратились.
Возник вопрос:
     Почему если W и H изменяютя перед каждым вызовом QWidget setGeometry(0,0,W,H),
 то все нормально центруется, если W и H  НЕ изменять - прыжок в левый верхний угол,
 хотя его родителю QScrollArea сказано setAlignment(Qt::AlignCenter),
 с resize() такого нет.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #12 : Декабрь 02, 2009, 13:02 »

Под вращением понимаются повороты на 90/180 градусов каждый из которых обрабатывается отдельно.Хмм...
можно все вместе обаботать,но это дело вкуса и опыта

И кто Вам сказал что угол может быть только до 360? Улыбающийся
нужно вращение только на угол кратный 90 + приведение угла в методе fitRotate() из чего и следует
 утверждение о возможных значениях углов.
Цель не в том чтобы похвалиться "я, мол, любые вращения делаю". Просто гораздо проще и лучше реализовать одну операцию (вращение) вместо того чтобы разбирать N ее частных случаев. Разумеется, для пользователя/преподавателя Вы оставите только нужные углы. 

Возник вопрос:
     Почему если W и H изменяютя перед каждым вызовом QWidget setGeometry(0,0,W,H),
 то все нормально центруется, если W и H  НЕ изменять - прыжок в левый верхний угол,
 хотя его родителю QScrollArea сказано setAlignment(Qt::AlignCenter),
 с resize() такого нет.
Открываем исходники Qt (а еще лучше шагаем в отладчике) и смотрим почему Улыбающийся (хотя это может быть непросто)
Записан
nozog
Гость
« Ответ #13 : Декабрь 03, 2009, 07:58 »

Открываем исходники Qt (а еще лучше шагаем в отладчике) и смотрим почему Улыбающийся (хотя это может быть непросто)
Ожидал что-то вроде: "читай внимательнее хелп" или как говориться "RTFM" Подмигивающий

Кстати, копался в исходниках на предмет сообщения "QImage: out of memory, returning null image",
но ничего путного так и не нашел. Толи лыжи не едут толи я плохо искал.
Пошел разбираться с setGeometry()...



Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.083 секунд. Запросов: 22.