Force wxImage::Rotate to produce white background Topic is solved

If you are using the main C++ distribution of wxWidgets, Feel free to ask any question related to wxWidgets development here. This means questions regarding to C++ and wxWidgets, not compile problems.
Post Reply
liew
In need of some credit
In need of some credit
Posts: 2
Joined: Tue Jan 16, 2018 3:38 pm

Force wxImage::Rotate to produce white background

Post by liew »

Please take a look at the following image:

Image

Setting mask to the rotated image allowed me to achieve white background when image is displayed on the canvas, but it won't be possible to save it with white background or rotate it again. I was wondering - is there a way to do force rotating mechanism to use white colour for background? Or maybe it's possible to merge image with its mask?
User avatar
eranon
Can't get richer than this
Can't get richer than this
Posts: 867
Joined: Sun May 13, 2012 11:42 pm
Location: France
Contact:

Re: Force wxImage::Rotate to produce white background

Post by eranon »

You don't show any code... When do you draw your image? During OnPaint handler?
[Ind. dev. - wxWidgets 3.0/3.1 under "Win 7 64-bit, TDM64-GCC" + "OS X 10.9, LLVM Clang"]
User avatar
doublemax
Moderator
Moderator
Posts: 19159
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: Force wxImage::Rotate to produce white background

Post by doublemax »

Use SetMaskColor( 255,255,255 ) before rotating and SetMask(false) before saving and you should get the correct result.

Tested with this:

Code: Select all

::wxInitAllImageHandlers();

const double halfC = M_PI / 180;
wxImage img("d:\\_test.jpg", wxBITMAP_TYPE_JPEG );

img.SetMaskColour(255,255,255);
wxImage img1 = img.Rotate(45.0f * halfC, wxPoint(img.GetWidth()/2, img.GetHeight()/2), false );
img1.SetMask(false);
img1.SaveFile( "d:\\_test_rot1.png", wxBITMAP_TYPE_PNG );

img1.SetMaskColour(255,255,255);
wxImage img2 = img1.Rotate(45.0f * halfC, wxPoint(img1.GetWidth()/2, img1.GetHeight()/2), false );
img2.SetMask(false);
img2.SaveFile( "d:\\_test_rot2.png", wxBITMAP_TYPE_PNG );
Use the source, Luke!
User avatar
eranon
Can't get richer than this
Can't get richer than this
Posts: 867
Joined: Sun May 13, 2012 11:42 pm
Location: France
Contact:

Re: Force wxImage::Rotate to produce white background

Post by eranon »

Does a mask is really necessary here, doublemax? Is the interpolating parameter of wxImage::Rotate not enough (unless the fact we have to clear the background if a previous image has been drawn of course, but it's not the question of the op)?
[Ind. dev. - wxWidgets 3.0/3.1 under "Win 7 64-bit, TDM64-GCC" + "OS X 10.9, LLVM Clang"]
User avatar
doublemax
Moderator
Moderator
Posts: 19159
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: Force wxImage::Rotate to produce white background

Post by doublemax »

I don't think the interpolating parameter is relevant here. If the image is rotated, the target image is bigger than the original one, and the empty corners need to be filled with something. By default this is black and the mask color is the only way to change this.
Use the source, Luke!
liew
In need of some credit
In need of some credit
Posts: 2
Joined: Tue Jan 16, 2018 3:38 pm

Re: Force wxImage::Rotate to produce white background

Post by liew »

Use SetMaskColor( 255,255,255 ) before rotating and SetMask(false) before saving and you should get the correct result.
This worked like a charm! Many thanks!
User avatar
eranon
Can't get richer than this
Can't get richer than this
Posts: 867
Joined: Sun May 13, 2012 11:42 pm
Location: France
Contact:

Re: Force wxImage::Rotate to produce white background

Post by eranon »

doublemax wrote:I don't think the interpolating parameter is relevant here. If the image is rotated, the target image is bigger than the original one, and the empty corners need to be filled with something. By default this is black and the mask color is the only way to change this.
In theory, I agree with you, doublemax, but in practice in the quick test I written below, when I raise the interpolation flag, it works, while when it's down, I get the black background around:

Code: Select all

// YOU HAVE TO CLICK ONE TIME TO START THE ROTATIONS SEQUENCE
#include "wx/wx.h"
#include <wx/stdpaths.h>
#include <wx/filename.h>

class MinDialog : public wxDialog
{
    public:
		MinDialog() : wxDialog(NULL, wxID_ANY, wxString("Minimal Dialog"),
                              wxDefaultPosition, wxSize(800, 800)){
			wxString exe_dir = wxFileName(wxStandardPaths::Get().GetExecutablePath()).GetPath();
			m_img = wxImage(exe_dir + "/test.png", wxBITMAP_TYPE_PNG);
			m_timer = new wxTimer(this);
			SetBackgroundColour (*wxBLUE);
			ClearBackground();
			Connect(m_timer->GetId(), wxEVT_TIMER, wxTimerEventHandler(MinDialog::OnTimer), NULL, this);
			Connect(wxEVT_LEFT_DOWN, wxMouseEventHandler(MinDialog::OnDown));
			Connect(wxEVT_PAINT,(wxObjectEventFunction) &MinDialog::OnPaint);}

	private:
		wxImage m_img;
		wxTimer* m_timer;

		void OnDown(wxMouseEvent& event){
			wxUnusedVar(event);
			m_timer->Start(1000);}

		void OnTimer(wxTimerEvent& event){
			wxUnusedVar(event);
			static int angle = 0;
			angle += 45;
			
			// with "false" rather than "true" below, it doesn't work (black around the rotated image)
			m_img = m_img.Rotate(angle, wxPoint(m_img.GetWidth()/2, m_img.GetHeight()/2), true);
			
			Refresh(false);}

		void OnPaint (wxPaintEvent &){
			wxPaintDC dc(this);
			dc.DrawBitmap(m_img, 300, 300);}
};

class MinApp : public wxApp
{
	bool OnInit(){
		wxInitAllImageHandlers();
        MinDialog dlg;
        dlg.ShowModal();
        return false;}
};

DECLARE_APP(MinApp)
IMPLEMENT_APP(MinApp)
What do you think? Maybe I missed a point in the original question, but where?
Attachments
test image used in the code above
test image used in the code above
test.png (72.95 KiB) Viewed 1869 times
[Ind. dev. - wxWidgets 3.0/3.1 under "Win 7 64-bit, TDM64-GCC" + "OS X 10.9, LLVM Clang"]
User avatar
doublemax
Moderator
Moderator
Posts: 19159
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: Force wxImage::Rotate to produce white background

Post by doublemax »

I think the issue was what happens when you save the rotated image. In one case you will get the rotated image with the "new" parts transparent. But if you want the whole image to be opaque with a white background, you need the other method.
Use the source, Luke!
User avatar
eranon
Can't get richer than this
Can't get richer than this
Posts: 867
Joined: Sun May 13, 2012 11:42 pm
Location: France
Contact:

Re: Force wxImage::Rotate to produce white background

Post by eranon »

You're right, doublemax! Saving the rotated images during sequence, it confirms the extra parts are transparents: this explains that :)

Code: Select all

// Just after rotation in OnTimer()
m_img.SaveFile(wxString::Format("%s/rot_%i.png", m_exe_dir, angle));
Attachments
rotated with transparency around
rotated with transparency around
rot_45.png (86.53 KiB) Viewed 1864 times
[Ind. dev. - wxWidgets 3.0/3.1 under "Win 7 64-bit, TDM64-GCC" + "OS X 10.9, LLVM Clang"]
Post Reply