How to properly display a picture ?
Moderator: Rathinagiri
How to properly display a picture ?
Handling pictures seems to be a weak point in Qt or I didn´t get the clue.
Assumed I define a BITMAP control with 300x300 points.
Now I want to display a picture with 400*600 points (portrait) and I want to see the whole picture. In this case SCALEDTOHEIGHT = .T. would be the right commands, the picture would be scaled down to 200*300 points.
If the picture has 600*400 (landscape) points I have to use SCALEDTOWIDTH = .T. to scale it down to 300*200 points.
What if I don´t know the size of the picture before (portrait or landscape)? I first thought SCALEDTOWIDTH = .T. and SCALEDTOHEIGHT = .T. would do it but in this case SCALEDTOWIDTH "wins" and portrait pictures are cropped.
Assumed I define a BITMAP control with 300x300 points.
Now I want to display a picture with 400*600 points (portrait) and I want to see the whole picture. In this case SCALEDTOHEIGHT = .T. would be the right commands, the picture would be scaled down to 200*300 points.
If the picture has 600*400 (landscape) points I have to use SCALEDTOWIDTH = .T. to scale it down to 300*200 points.
What if I don´t know the size of the picture before (portrait or landscape)? I first thought SCALEDTOWIDTH = .T. and SCALEDTOHEIGHT = .T. would do it but in this case SCALEDTOWIDTH "wins" and portrait pictures are cropped.
Re: How to properly display a picture ?
I found the solution and it´s much better then I expected.
I wanted a picture that is smaller than the bitmap control not to be scaled up, but a picture, who is bigger to be scaled down to the size of the control (without stretching it).
My way was to overload the BITMAP class with my own MYBITMAP class.
To define my bitmap I use this code:
And here is my MYBITMAP class:
I wanted a picture that is smaller than the bitmap control not to be scaled up, but a picture, who is bigger to be scaled down to the size of the control (without stretching it).
My way was to overload the BITMAP class with my own MYBITMAP class.
To define my bitmap I use this code:
Code: Select all
With Object MYBITMAP():New( "oBitmap" )
:Row := 100
:Col := 100
:Width := 300
:Height := 3000
:Picture := <cImagefile>
:Alignment := LBL_CENTER // smaller pictures should be centered
:VAlignment := LBL_VCENTER
end
Code: Select all
/*==============================================================================
MYBITMAP class
==============================================================================*/
CLASS MYBITMAP FROM BITMAP
DATA cClass INIT "MYBITMAP"
// Methods
METHOD New
METHOD Picture SETGET
ENDCLASS
/*..............................................................................
New
..............................................................................*/
METHOD New( cName, oParent ) CLASS MYBITMAP
Super:New( cName, oParent )
RETURN Self
/*..............................................................................
Picture
..............................................................................*/
METHOD Picture( cValue ) CLASS MYBITMAP
LOCAL oIMG
IF Pcount() == 0
RETURN ::cPicture
ELSEIF Pcount() == 1
::cPicture := cValue
IF ::lCreated
oImg := QPixmap( cValue )
IF oImg:width() == 0 .and. left( cValue, 1 ) != ":"
cValue := ":" +cValue
oImg := QPixmap( cValue )
IF oImg:width() > 0
::cPicture := cValue
ENDIF
ENDIF
IF oImg:width() > ::oQTObject:width .AND. oImg:width() > oImg:height() // picture too width and landscape?
oIMG := oIMG:scaledToWidth( ::oQTObject:width )
ELSEIF oImg:height() > ::oQTObject:height .AND. oImg:height() > oImg:width() // picture too height and portrait?
oIMG := oIMG:scaledToHeight( ::oQTObject:height )
ENDIF
::oQTObject:setPixmap( oIMG )
ENDIF
ENDIF
RETURN NIL
Re: How to properly display a picture ?
GOOD GOOD GOOD !!!
The power of real OOP !
Do you need to expand/modify the behaviour of a class ? Derive from it and change the code... sometimes it is easy, like here, sometimes is a bit more complicated since the method may be long and complex, but it is definitively the way to go !!!
Since in New() you are just calling super:New() I think you can remove the definition of New() method.
Francesco
The power of real OOP !
Do you need to expand/modify the behaviour of a class ? Derive from it and change the code... sometimes it is easy, like here, sometimes is a bit more complicated since the method may be long and complex, but it is definitively the way to go !!!
Since in New() you are just calling super:New() I think you can remove the definition of New() method.
Francesco
Re: How to properly display a picture ?
That´s right, thank you.mrduck wrote: Since in New() you are just calling super:New() I think you can remove the definition of New() method.
Re: How to properly display a picture ?
Hi Ricci, could you please do a test with this source code about BITMAP.
Code: Select all
#include "hbclass.ch"
#include "common.ch"
#include "hbqtgui.ch"
#include "hmg_qtimage.ch"
#include "hmg.ch"
/*==============================================================================
BITMAP class
==============================================================================*/
CLASS BITMAP FROM LABEL
DATA cClass INIT "BITMAP"
// data: please preserve alphabetic order.
DATA oImage INIT NIL PROTECTED
DATA cPicture INIT '' PROTECTED
DATA lScaledToHeight INIT .F. PROTECTED
DATA lScaledToWidth INIT .F. PROTECTED
DATA lStretch INIT .T. PROTECTED
DATA nAspectRatio INIT 1 PROTECTED
// Methods: please preserve alphabetic order. Methods "New" and "Create" must be the first if present
METHOD New
METHOD Create
METHOD AspectRatio SETGET
METHOD Picture SETGET
METHOD ScaledToHeight SETGET
METHOD ScaledToWidth SETGET
METHOD Stretch SETGET
METHOD __HmgConnectEv PROTECTED
METHOD __HmgDisConnectEv PROTECTED
METHOD __HmgOnSizeExec PROTECTED
METHOD __HmgUpdateImage PROTECTED
ENDCLASS
/*..............................................................................
New
..............................................................................*/
METHOD New( cName, oParent ) CLASS BITMAP
Super:New( cName, oParent )
/* this lines are already present within LABEL.class */
// IF hb_IsNil( ::oParent ) == .T.
// ::oQTObject := QLabel()
// ELSE
// ::oQTObject := QLabel( ::oParent:QtObject )
// ENDIF
RETURN Self
/*..............................................................................
Create
..............................................................................*/
METHOD Create() ClASS BITMAP
::lCreated := .T.
::__HmgUpdateImage()
::__HmgConnectEv()
RETURN Self
/*..............................................................................
AspectRatio
..............................................................................*/
METHOD AspectRatio( nValue ) CLASS BITMAP
IF PCOUNT() == 0
RETURN ::nAspectRatio
ELSEIF hb_IsNumeric( nValue ) == .T.
IF nValue == Qt_IgnoreAspectRatio .OR. nValue == Qt_KeepAspectRatio .OR. nValue == Qt_KeepAspectRatioByExpanding
::nAspectRatio := nValue
ENDIF
::__HmgUpdateImage()
ENDIF
RETURN Self
/*..............................................................................
Picture
..............................................................................*/
METHOD Picture( cValue ) CLASS BITMAP
IF PCOUNT() == 0
RETURN ::cPicture
ELSEIF PCOUNT() == 1
::cPicture := cValue
::__HmgUpdateImage()
ENDIF
RETURN NIL
/*..............................................................................
ScaledToHeight
..............................................................................*/
METHOD ScaledToHeight( lValue ) CLASS BITMAP
IF PCOUNT() == 0
RETURN ::lScaledToHeight
ELSEIF hb_IsLogical( lValue ) == .T.
::lScaledToHeight := lValue
IF ::lScaledToHeight == .T.
::lStretch := .F.
::lScaledToWidth := .F.
ENDIF
::__HmgUpdateImage()
ENDIF
RETURN NIL
/*..............................................................................
ScaledToWidth
..............................................................................*/
METHOD ScaledToWidth( lValue ) CLASS BITMAP
IF PCOUNT() == 0
RETURN ::lScaledToWidth
ELSEIF hb_IsLogical( lValue ) == .T.
::lScaledToWidth := lValue
IF ::lScaledToWidth == .T.
::lStretch := .F.
::lScaledToHeight := .F.
ENDIF
::__HmgUpdateImage()
ENDIF
RETURN NIL
/*..............................................................................
Stretch
..............................................................................*/
METHOD Stretch( lValue ) CLASS BITMAP
IF PCOUNT() == 0
RETURN ::lStretch // RETURN ::oQTObject:hasScaledContents()
ELSEIF hb_IsLogical( lValue ) == .T.
::lStretch := lValue
// ::oQTObject:setScaledContents( ::lStretch )
IF ::lStretch == .T.
::lScaledToWidth := .F.
::lScaledToHeight := .F.
ENDIF
::__HmgUpdateImage()
ENDIF
RETURN NIL
/*..............................................................................
__HmgConnectEv
ATTENTION: this is the most generic connector. Pay attention if you want add other event
..............................................................................*/
METHOD __HmgConnectEv() CLASS BITMAP
::oQtObject:connect( QEvent_Close, { |oEv| ::__HmgOnCloseExec(oEv) } )
::oQTObject:connect( QEvent_Resize , { || ::__HmgOnSizeExec() } )
RETURN Self
/*..............................................................................
__HmgDisconnectEv
ATTENTION: this is the most generic DISconnector. Pay attention if you want add other event
..............................................................................*/
METHOD __HmgDisconnectEv() CLASS BITMAP
::oQtObject:disconnect( QEvent_Close )
::oQTObject:disconnect( QEvent_Resize )
RETURN Self
/*..............................................................................
__HmgOnSizeExec
..............................................................................*/
METHOD __HmgOnSizeExec() CLASS BITMAP
LOCAL lQtEventStop := .F. // .F. means don't stop event hanlder, else .T. STOP see Harbour Changelog
IF ::IsCreated()
::__HmgUpdateImage()
ENDIF
RETURN lQtEventStop
/*..............................................................................
__HmgUpdateImage
..............................................................................*/
METHOD __HmgUpdateImage() CLASS BITMAP
LOCAL oQtImage, oQtWidgetSize, oQtPainter, oQtCenterPoint, oQtNewImage, nImageWidth, nImageHeight
IF ::IsCreated() == .T.
oQtImage := QPixmap()
oQtImage:load( ::cPicture )
IF oQtImage:IsNull()
// nothing to do: image is empty
RETURN NIL
ENDIF
// user want ImageWidth as the same of QLabel canvas
IF ::ScaledToWidth() == .T. .AND. ::Stretch() == .F.
oQtImage := oQtImage:scaledToWidth( ::oQTObject:width() ) // this keep aspect ratio
IF oQtImage:IsNull() == .F.
::oQTObject:setPixmap( oQtImage )
ENDIF
RETURN NIL
ENDIF
// user want ImageWidth as the same of QLabel canvas
IF ::ScaledToHeight() == .T. .AND. ::Stretch() == .F.
oQtImage := oQtImage:scaledToHeight( ::oQTObject:height() ) // this keep aspect ratio
IF oQtImage:IsNull() == .F.
::oQTObject:setPixmap( oQtImage )
ENDIF
RETURN NIL
ENDIF
// user want to fit as the same of QLabel canvas
IF ::Stretch() == .T.
nImageWidth := ::oQTObject:width()
nImageHeight := ::oQTObject:height()
ELSE
nImageWidth := IIF( oQtImage:width() > ::oQTObject:width(), ::oQTObject:width(), oQtImage:width() )
nImageHeight := IIF( oQtImage:height() > ::oQTObject:height(), ::oQTObject:height(), oQtImage:height() )
ENDIF
// this code to center image within QLabel canvas
oQtWidgetSize := ::oQtObject:size()
// start painter
oQtPainter := QPainter()
oQtNewImage := QImage( oQtWidgetSize:width(), oQtWidgetSize:height(), QImage_Format_ARGB32_Premultiplied )
oQtPainter:begin( oQtNewImage )
oQtCenterPoint := QPoint(0,0)
// reload and scaling image to the width and height desired
oQtImage:load( ::cPicture )
oQtImage := oQtImage:scaled( nImageWidth, nImageHeight, ::AspectRatio() ) //oQtImage := oQtImage:scaled( oQtWidgetSize, ::AspectRatio() )
IF oQtImage:IsNull()
// nothing to do: image is out of scaled
RETURN NIL
ENDIF
// Calculate image center position into screen
oQtCenterPoint:setX( ( oQtWidgetSize:width() - oQtImage:width() ) / 2 )
oQtCenterPoint:setY( ( oQtWidgetSize:height() - oQtImage:height() ) / 2 )
// Draw image
oQtPainter:drawPixmap( oQtCenterPoint, oQtImage )
// end painter
oQtPainter:end()
// set object PixMap
::oQTObject:setPixMap( QPixMap():fromImage( oQtNewImage ) )
oQtImage := NIL
oQtWidgetSize := NIL
oQtPainter := NIL
oQtCenterPoint := NIL
oQtNewImage := NIL
ENDIF
RETURN Self
Luigi from Italy
www.L3W.it
www.L3W.it
Re: How to properly display a picture ?
Luigi, your code is working well but ....
... due to the double :load() it is 50% slower.
... due to the double :load() it is 50% slower.
Re: How to properly display a picture ?
Luigi, this modified code will work the same but as fast as before and the user has more possibilities with scaling.
The center commands can be defined with
:Alignment := LBL_CENTER
:VAlignment := LBL_VCENTER
in the user program. In this way every alignment is possible.
The center commands can be defined with
:Alignment := LBL_CENTER
:VAlignment := LBL_VCENTER
in the user program. In this way every alignment is possible.
Code: Select all
#include "hbclass.ch"
#include "common.ch"
#include "hbqtgui.ch"
#include "hmg_qtimage.ch"
#include "hmg.ch"
/*==============================================================================
BITMAP class
==============================================================================*/
CLASS BITMAP FROM LABEL
DATA cClass INIT "BITMAP"
// data: please preserve alphabetic order.
DATA oImage INIT NIL PROTECTED
DATA cPicture INIT '' PROTECTED
DATA lScaledToHeight INIT .F. PROTECTED
DATA lScaledToWidth INIT .F. PROTECTED
DATA lStretch INIT .T. PROTECTED
DATA nAspectRatio INIT 1 PROTECTED
// Methods: please preserve alphabetic order. Methods "New" and "Create" must be the first if present
METHOD Create
METHOD AspectRatio SETGET
METHOD Picture SETGET
METHOD ScaledToHeight SETGET
METHOD ScaledToWidth SETGET
METHOD Stretch SETGET
METHOD __HmgConnectEv PROTECTED
METHOD __HmgDisConnectEv PROTECTED
METHOD __HmgOnSizeExec PROTECTED
METHOD __HmgUpdateImage PROTECTED
ENDCLASS
/*..............................................................................
Create
..............................................................................*/
METHOD Create() ClASS BITMAP
::lCreated := .T.
::__HmgUpdateImage()
::__HmgConnectEv()
RETURN Self
/*..............................................................................
AspectRatio
..............................................................................*/
METHOD AspectRatio( nValue ) CLASS BITMAP
IF PCOUNT() == 0
RETURN ::nAspectRatio
ELSEIF hb_IsNumeric( nValue ) == .T.
IF nValue == Qt_IgnoreAspectRatio .OR. nValue == Qt_KeepAspectRatio .OR. nValue == Qt_KeepAspectRatioByExpanding
::nAspectRatio := nValue
ENDIF
::__HmgUpdateImage()
ENDIF
RETURN Self
/*..............................................................................
Picture
..............................................................................*/
METHOD Picture( cValue ) CLASS BITMAP
IF PCOUNT() == 0
RETURN ::cPicture
ELSEIF PCOUNT() == 1
::cPicture := cValue
::__HmgUpdateImage()
ENDIF
RETURN NIL
/*..............................................................................
ScaledToHeight
..............................................................................*/
METHOD ScaledToHeight( lValue ) CLASS BITMAP
IF PCOUNT() == 0
RETURN ::lScaledToHeight
ELSEIF hb_IsLogical( lValue ) == .T.
::lScaledToHeight := lValue
IF ::lScaledToHeight == .T.
::lStretch := .F.
// ::lScaledToWidth := .F.
ENDIF
::__HmgUpdateImage()
ENDIF
RETURN NIL
/*..............................................................................
ScaledToWidth
..............................................................................*/
METHOD ScaledToWidth( lValue ) CLASS BITMAP
IF PCOUNT() == 0
RETURN ::lScaledToWidth
ELSEIF hb_IsLogical( lValue ) == .T.
::lScaledToWidth := lValue
IF ::lScaledToWidth == .T.
::lStretch := .F.
// ::lScaledToHeight := .F.
ENDIF
::__HmgUpdateImage()
ENDIF
RETURN NIL
/*..............................................................................
Stretch
..............................................................................*/
METHOD Stretch( lValue ) CLASS BITMAP
IF PCOUNT() == 0
RETURN ::lStretch // RETURN ::oQTObject:hasScaledContents()
ELSEIF hb_IsLogical( lValue ) == .T.
::lStretch := lValue
::oQTObject:setScaledContents( ::lStretch )
IF ::lStretch == .T.
::lScaledToWidth := .F.
::lScaledToHeight := .F.
ENDIF
::__HmgUpdateImage()
ENDIF
RETURN NIL
/*..............................................................................
__HmgConnectEv
ATTENTION: this is the most generic connector. Pay attention if you want add other event
..............................................................................*/
METHOD __HmgConnectEv() CLASS BITMAP
::oQtObject:connect( QEvent_Close, { |oEv| ::__HmgOnCloseExec(oEv) } )
::oQTObject:connect( QEvent_Resize , { || ::__HmgOnSizeExec() } )
RETURN Self
/*..............................................................................
__HmgDisconnectEv
ATTENTION: this is the most generic DISconnector. Pay attention if you want add other event
..............................................................................*/
METHOD __HmgDisconnectEv() CLASS BITMAP
::oQtObject:disconnect( QEvent_Close )
::oQTObject:disconnect( QEvent_Resize )
RETURN Self
/*..............................................................................
__HmgOnSizeExec
..............................................................................*/
METHOD __HmgOnSizeExec() CLASS BITMAP
LOCAL lQtEventStop := .F. // .F. means don't stop event hanlder, else .T. STOP see Harbour Changelog
IF ::IsCreated()
::__HmgUpdateImage()
ENDIF
RETURN lQtEventStop
/*..............................................................................
__HmgUpdateImage
..............................................................................*/
METHOD __HmgUpdateImage() CLASS BITMAP
LOCAL oQtImage, oQtWidgetSize, oQtPainter, oQtCenterPoint, oQtNewImage, nImageWidth, nImageHeight
IF ::IsCreated() == .T.
oQtImage := QPixmap()
oQtImage:load( ::cPicture )
IF oQtImage:IsNull()
// nothing to do: image is empty
RETURN NIL
ENDIF
// user want streched image
IF ::Stretch() == .T.
::oQTObject:setPixmap( oQtImage )
RETURN NIL
ENDIF
// user always want to scale, depending on the orientation
IF ::ScaledToWidth() == .T. .AND. ::ScaledToHeight() == .T.
IF oQtImage:width() > oQtImage:height()
oQtImage := oQtImage:scaledToWidth( ::oQTObject:width() )
ELSE
oQtImage := oQtImage:scaledToHeight( ::oQTObject:height() )
ENDIF
IF oQtImage:IsNull() == .F.
::oQTObject:setPixmap( oQtImage )
ENDIF
RETURN NIL
ENDIF
// user want ImageWidth as the same of QLabel canvas
IF ::ScaledToWidth() == .T.
oQtImage := oQtImage:scaledToWidth( ::oQTObject:width() ) // this keep aspect ratio
IF oQtImage:IsNull() == .F.
::oQTObject:setPixmap( oQtImage )
ENDIF
RETURN NIL
ENDIF
// user want ImageWidth as the same of QLabel canvas
IF ::ScaledToHeight() == .T.
oQtImage := oQtImage:scaledToHeight( ::oQTObject:height() ) // this keep aspect ratio
IF oQtImage:IsNull() == .F.
::oQTObject:setPixmap( oQtImage )
ENDIF
RETURN NIL
ENDIF
// user want to fit as the same of QLabel canvas
IF oQtImage:width() > ::oQTObject:width .AND. oQtImage:width() > oQtImage:height()
oQtImage := oQtImage:scaledToWidth( ::oQTObject:width() )
ELSEIF oQtImage:height() > ::oQTObject:height .AND. oQtImage:height() > oQtImage:width()
oQtImage := oQtImage:scaledToHeight( ::oQTObject:height() )
ENDIF
IF oQtImage:IsNull() == .F.
::oQTObject:setPixmap( oQtImage )
ENDIF
ENDIF
RETURN Self
Last edited by Ricci on Tue Oct 11, 2011 8:58 pm, edited 1 time in total.
Re: How to properly display a picture ?
Explanation about the effect of the parameters:
:Stretch := .F.
the picture ist scaled up/down in hor. and vert. direction until it fits the size of the control, proportions are usually lost, the full picture is displayed,alignment/valignment is ineffective
:Stretch := .F. + :ScaledToHeight := .T. + :ScaledToWidth := .T.
the picture ist scaled up/down in hor. or vert. direction (depending on its orientation) until the bigger size fits the size of the control, the full picture is displayed, proportions remains, alignment/valignment is effective
:Stretch := .F. + :ScaledToHeight := .T. + :ScaledToWidth := .F.
the picture ist scaled up/down in vert. direction, proportions remains, alignment is effective, hor. parts are lost if the picture is landscape
:Stretch := .F. + :ScaledToHeight := .F. + :ScaledToWidth := .T.
the picture ist scaled up/down in hor. direction, proportions remains, valignment is effective, ver. parts are lost if the picture is portrait
:Stretch := .F. + :ScaledToHeight := .F. + :ScaledToWidth := .F.
the picture ist scaled down in hor. or vert. direction (depending on its orientation) until the bigger size fits the size of the control, the full picture is displayed, proportions remains, alignment/valignment is effective, pictures that are smaller than the size of the control are not scaled up
:Stretch := .F.
the picture ist scaled up/down in hor. and vert. direction until it fits the size of the control, proportions are usually lost, the full picture is displayed,alignment/valignment is ineffective
:Stretch := .F. + :ScaledToHeight := .T. + :ScaledToWidth := .T.
the picture ist scaled up/down in hor. or vert. direction (depending on its orientation) until the bigger size fits the size of the control, the full picture is displayed, proportions remains, alignment/valignment is effective
:Stretch := .F. + :ScaledToHeight := .T. + :ScaledToWidth := .F.
the picture ist scaled up/down in vert. direction, proportions remains, alignment is effective, hor. parts are lost if the picture is landscape
:Stretch := .F. + :ScaledToHeight := .F. + :ScaledToWidth := .T.
the picture ist scaled up/down in hor. direction, proportions remains, valignment is effective, ver. parts are lost if the picture is portrait
:Stretch := .F. + :ScaledToHeight := .F. + :ScaledToWidth := .F.
the picture ist scaled down in hor. or vert. direction (depending on its orientation) until the bigger size fits the size of the control, the full picture is displayed, proportions remains, alignment/valignment is effective, pictures that are smaller than the size of the control are not scaled up