From 37ba70a520519fd2fe4f11400f1383fa37ae7cd9 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sat, 8 Sep 2007 18:32:36 +0000 Subject: [PATCH] added support for reading resolution information from TIFF, JPEG and BMP formats; corrected some bugs with saving resolution; added command allowing to see the image resolution (if available) to the sample (heavily modified patch 1790546) git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@48612 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- docs/changes.txt | 1 + samples/image/image.cpp | 89 ++++++++++++++++++++++++++++++++++------- src/common/imagbmp.cpp | 41 ++++++++++++++++++- src/common/imagjpeg.cpp | 11 +++++ src/common/imagtiff.cpp | 73 +++++++++++++++++++++++++++++---- 5 files changed, 191 insertions(+), 24 deletions(-) diff --git a/docs/changes.txt b/docs/changes.txt index 6cb0b685f8..7a26570c94 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -180,6 +180,7 @@ All (GUI): - Added wxToolTip::SetAutoPop() and SetReshow() (Jan Knepper) - Added wxTaskBarIcon::Destroy() - Added XRC handler for wxSearchCtrl (Sander Berents) +- Read image resolution from TIFF, JPEG and BMP images (Maycon Aparecido Gasoto) wxGTK: diff --git a/samples/image/image.cpp b/samples/image/image.cpp index 2ea3512b84..a365d34310 100644 --- a/samples/image/image.cpp +++ b/samples/image/image.cpp @@ -118,6 +118,7 @@ public: void OnAbout( wxCommandEvent &event ); void OnNewFrame( wxCommandEvent &event ); + void OnImageInfo( wxCommandEvent &event ); #ifdef wxHAVE_RAW_BITMAP void OnTestRawBitmap( wxCommandEvent &event ); #endif // wxHAVE_RAW_BITMAP @@ -131,6 +132,13 @@ public: MyCanvas *m_canvas; private: + // ask user for the file name and try to load an image from it + // + // return the file path on success, empty string if we failed to load the + // image or were cancelled by user + static wxString LoadUserImage(wxImage& image); + + DECLARE_DYNAMIC_CLASS(MyFrame) DECLARE_EVENT_TABLE() }; @@ -1101,17 +1109,19 @@ enum ID_QUIT = wxID_EXIT, ID_ABOUT = wxID_ABOUT, ID_NEW = 100, - ID_SHOWRAW = 101 + ID_INFO, + ID_SHOWRAW }; IMPLEMENT_DYNAMIC_CLASS( MyFrame, wxFrame ) -BEGIN_EVENT_TABLE(MyFrame,wxFrame) +BEGIN_EVENT_TABLE(MyFrame, wxFrame) EVT_MENU (ID_ABOUT, MyFrame::OnAbout) EVT_MENU (ID_QUIT, MyFrame::OnQuit) - EVT_MENU (ID_NEW, MyFrame::OnNewFrame) + EVT_MENU (ID_NEW, MyFrame::OnNewFrame) + EVT_MENU (ID_INFO, MyFrame::OnImageInfo) #ifdef wxHAVE_RAW_BITMAP - EVT_MENU (ID_SHOWRAW, MyFrame::OnTestRawBitmap) + EVT_MENU (ID_SHOWRAW, MyFrame::OnTestRawBitmap) #endif #if wxUSE_CLIPBOARD @@ -1128,8 +1138,9 @@ MyFrame::MyFrame() wxMenu *menuImage = new wxMenu; menuImage->Append( ID_NEW, _T("&Show any image...\tCtrl-O")); - + menuImage->Append( ID_INFO, _T("Show image &information...\tCtrl-I")); #ifdef wxHAVE_RAW_BITMAP + menuImage->AppendSeparator(); menuImage->Append( ID_SHOWRAW, _T("Test &raw bitmap...\tCtrl-R")); #endif menuImage->AppendSeparator(); @@ -1171,23 +1182,71 @@ void MyFrame::OnAbout( wxCommandEvent &WXUNUSED(event) ) _T("About wxImage Demo"), wxICON_INFORMATION | wxOK ); } -void MyFrame::OnNewFrame( wxCommandEvent &WXUNUSED(event) ) +wxString MyFrame::LoadUserImage(wxImage& image) { + wxString filename; + #if wxUSE_FILEDLG - wxString filename = wxFileSelector(_T("Select image file")); - if ( !filename ) - return; + filename = wxFileSelector(_T("Select image file")); + if ( !filename.empty() ) + { + if ( !image.LoadFile(filename) ) + { + wxLogError(_T("Couldn't load image from '%s'."), filename.c_str()); + return wxEmptyString; + } + } +#endif // wxUSE_FILEDLG + + return filename; +} + +void MyFrame::OnNewFrame( wxCommandEvent &WXUNUSED(event) ) +{ wxImage image; - if ( !image.LoadFile(filename) ) + wxString filename = LoadUserImage(image); + if ( !filename.empty() ) + (new MyImageFrame(this, filename, wxBitmap(image)))->Show(); +} + +void MyFrame::OnImageInfo( wxCommandEvent &WXUNUSED(event) ) +{ + wxImage image; + if ( !LoadUserImage(image).empty() ) { - wxLogError(_T("Couldn't load image from '%s'."), filename.c_str()); + // TODO: show more information about the file + wxString info = wxString::Format("Image size: %dx%d", + image.GetWidth(), + image.GetHeight()); + + int xres = image.GetOptionInt(wxIMAGE_OPTION_RESOLUTIONX), + yres = image.GetOptionInt(wxIMAGE_OPTION_RESOLUTIONY); + if ( xres || yres ) + { + info += wxString::Format("\nResolution: %dx%d", xres, yres); + switch ( image.GetOptionInt(wxIMAGE_OPTION_RESOLUTIONUNIT) ) + { + default: + wxFAIL_MSG( "unknown image resolution units" ); + // fall through - return; - } + case wxIMAGE_RESOLUTION_NONE: + info += " in default units"; + break; - (new MyImageFrame(this, filename, wxBitmap(image)))->Show(); -#endif // wxUSE_FILEDLG + case wxIMAGE_RESOLUTION_INCHES: + info += " in"; + break; + + case wxIMAGE_RESOLUTION_CM: + info += " cm"; + break; + } + } + + wxLogMessage("%s", info); + } } #ifdef wxHAVE_RAW_BITMAP diff --git a/src/common/imagbmp.cpp b/src/common/imagbmp.cpp index 5f45ba9207..76d4532725 100644 --- a/src/common/imagbmp.cpp +++ b/src/common/imagbmp.cpp @@ -27,6 +27,7 @@ #include "wx/bitmap.h" #include "wx/palette.h" #include "wx/intl.h" + #include "wx/math.h" #endif #include "wx/filefn.h" @@ -154,7 +155,7 @@ bool wxBMPHandler::SaveDib(wxImage *image, wxUint16 bpp; // bits per pixel wxUint32 compression; // compression method wxUint32 size_of_bmp; // size of the bitmap - wxUint32 h_res, v_res; // image resolution in dpi + wxUint32 h_res, v_res; // image resolution in pixels-per-meter wxUint32 num_clrs; // number of colors used wxUint32 num_signif_clrs;// number of significant colors } hdr; @@ -181,7 +182,37 @@ bool wxBMPHandler::SaveDib(wxImage *image, hdr.bpp = wxUINT16_SWAP_ON_BE(bpp); hdr.compression = 0; // RGB uncompressed hdr.size_of_bmp = wxUINT32_SWAP_ON_BE(row_width * image->GetHeight()); - hdr.h_res = hdr.v_res = wxUINT32_SWAP_ON_BE(72); // 72dpi is standard + + // get the resolution from the image options or fall back to 72dpi standard + // for the BMP format if not specified + wxUint32 hres = image->GetOptionInt(wxIMAGE_OPTION_RESOLUTIONX), + vres = image->GetOptionInt(wxIMAGE_OPTION_RESOLUTIONY); + switch ( image->GetOptionInt(wxIMAGE_OPTION_RESOLUTION) ) + { + default: + wxFAIL_MSG( _T("unexpected image resolution units") ); + // fall through + + case wxIMAGE_RESOLUTION_NONE: + hres = + vres = 72; + // fall through to convert it to correct units + + case wxIMAGE_RESOLUTION_INCHES: + // convert resolution in inches to resolution in centimeters + hres *= 100*mm2inches; + vres *= 100*mm2inches; + // fall through to convert it to resolution in meters + + case wxIMAGE_RESOLUTION_CM: + // convert resolution in centimeters to resolution in meters + hres *= 100; + vres *= 100; + break; + } + + hdr.h_res = wxUINT32_SWAP_ON_BE(hres); + hdr.v_res = wxUINT32_SWAP_ON_BE(vres); hdr.num_clrs = wxUINT32_SWAP_ON_BE(palette_size); // # colors in colormap hdr.num_signif_clrs = 0; // all colors are significant @@ -906,6 +937,7 @@ bool wxBMPHandler::LoadDib(wxImage *image, wxInputStream& stream, } stream.Read(dbuf, 4 * 2); + int ncolors = wxINT32_SWAP_ON_BE( (int)dbuf[0] ); if (ncolors == 0) ncolors = 1 << bpp; @@ -944,6 +976,11 @@ bool wxBMPHandler::LoadDib(wxImage *image, wxInputStream& stream, } + // the resolution in the bitmap header is in meters, convert to centimeters + image->SetOption(wxIMAGE_OPTION_RESOLUTIONUNIT, wxIMAGE_RESOLUTION_CM); + image->SetOption(wxIMAGE_OPTION_RESOLUTIONX, dbuf[2]/100); + image->SetOption(wxIMAGE_OPTION_RESOLUTIONY, dbuf[3]/100); + return true; } diff --git a/src/common/imagjpeg.cpp b/src/common/imagjpeg.cpp index 86dfa2da77..d045596065 100644 --- a/src/common/imagjpeg.cpp +++ b/src/common/imagjpeg.cpp @@ -310,6 +310,17 @@ bool wxJPEGHandler::LoadFile( wxImage *image, wxInputStream& stream, bool verbos } } + // set up resolution if available: it's part of optional JFIF APP0 chunk + if ( cinfo.saw_JFIF_marker ) + { + image->SetOption(wxIMAGE_OPTION_RESOLUTIONX, cinfo.X_density); + image->SetOption(wxIMAGE_OPTION_RESOLUTIONY, cinfo.Y_density); + + // we use the same values for this option as libjpeg so we don't need + // any conversion here + image->SetOption(wxIMAGE_OPTION_RESOLUTIONUNIT, cinfo.density_unit); + } + jpeg_finish_decompress( &cinfo ); jpeg_destroy_decompress( &cinfo ); return true; diff --git a/src/common/imagtiff.cpp b/src/common/imagtiff.cpp index 6a2d5b445a..49c76fba7c 100644 --- a/src/common/imagtiff.cpp +++ b/src/common/imagtiff.cpp @@ -344,6 +344,43 @@ bool wxTIFFHandler::LoadFile( wxImage *image, wxInputStream& stream, bool verbos alpha -= 2*w; } + // set the image resolution if it's available + uint16 tiffRes; + if ( TIFFGetField(tif, TIFFTAG_RESOLUTIONUNIT, &tiffRes) ) + { + wxImageResolution res; + switch ( tiffRes ) + { + default: + wxLogWarning(_("Unknown TIFF resolution unit %d ignored"), + tiffRes); + // fall through + + case RESUNIT_NONE: + res = wxIMAGE_RESOLUTION_NONE; + break; + + case RESUNIT_INCH: + res = wxIMAGE_RESOLUTION_INCHES; + break; + + case RESUNIT_CENTIMETER: + res = wxIMAGE_RESOLUTION_CM; + break; + } + + if ( res != wxIMAGE_RESOLUTION_NONE ) + { + float xres, yres; + if ( TIFFGetField(tif, TIFFTAG_XRESOLUTION, &xres) ) + image->SetOption(wxIMAGE_OPTION_RESOLUTIONX, xres); + + if ( TIFFGetField(tif, TIFFTAG_YRESOLUTION, &yres) ) + image->SetOption(wxIMAGE_OPTION_RESOLUTIONY, yres); + } + } + + _TIFFfree( raster ); TIFFClose( tif ); @@ -386,22 +423,44 @@ bool wxTIFFHandler::SaveFile( wxImage *image, wxOutputStream& stream, bool verbo TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT); TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); - if ( image->HasOption(wxIMAGE_OPTION_RESOLUTIONX) && - image->HasOption(wxIMAGE_OPTION_RESOLUTIONY) ) + // save the image resolution if we have it + int xres, yres; + const wxImageResolution res = GetResolutionFromOptions(*image, &xres, &yres); + uint16 tiffRes; + switch ( res ) { - TIFFSetField(tif, TIFFTAG_XRESOLUTION, - (float)image->GetOptionInt(wxIMAGE_OPTION_RESOLUTIONX)); - TIFFSetField(tif, TIFFTAG_YRESOLUTION, - (float)image->GetOptionInt(wxIMAGE_OPTION_RESOLUTIONY)); + default: + wxFAIL_MSG( _T("unknown image resolution units") ); + // fall through + + case wxIMAGE_RESOLUTION_NONE: + tiffRes = RESUNIT_NONE; + break; + + case wxIMAGE_RESOLUTION_INCHES: + tiffRes = RESUNIT_INCH; + break; + + case wxIMAGE_RESOLUTION_CM: + tiffRes = RESUNIT_CENTIMETER; + break; } + if ( tiffRes != RESUNIT_NONE ) + { + TIFFSetField(tif, TIFFTAG_RESOLUTIONUNIT, tiffRes); + TIFFSetField(tif, TIFFTAG_XRESOLUTION, (float)xres); + TIFFSetField(tif, TIFFTAG_YRESOLUTION, (float)yres); + } + + int spp = image->GetOptionInt(wxIMAGE_OPTION_SAMPLESPERPIXEL); if ( !spp ) spp = 3; int bpp = image->GetOptionInt(wxIMAGE_OPTION_BITSPERSAMPLE); if ( !bpp ) - bpp=8; + bpp = 8; int compression = image->GetOptionInt(wxIMAGE_OPTION_COMPRESSION); if ( !compression ) -- 2.47.2