From 692613e554e449ae9c0786a1144dea223b4f958f Mon Sep 17 00:00:00 2001 From: kgv Date: Mon, 10 Sep 2012 14:30:46 +0400 Subject: [PATCH] 0023272: Image comparison algorithm A new class Image_Diff for comparison of images and a draw-command "diffimage", which compares 2 images. Image_PixMap redesigned to provide interface for low-level image operations. New Image_AlienPixMap class now intended for Save/Load functionality. Aspect_PixMap class dropped. Xw_PixMap and WNT_PixMap classes now do not inherit from Aspect_PixMap and deprecated. ToPixMap methods now retrieve Image_PixMap as argument. Conflicts: src/ViewerTest/ViewerTest.cxx Remarks applied Fix compilation (correct merging error) Eliminated Aspect <-> Image cyclic dependency Fixed GIF dump in case of BGR32 image format --- src/Aspect/Aspect.cdl | 4 - src/Aspect/Aspect_PixMap.cdl | 92 --- src/Aspect/Aspect_PixMap.cxx | 52 -- src/Aspect/Aspect_Window.cdl | 7 - src/Draw/Draw_Window.cxx | 120 ++- src/Graphic3d/FILES | 1 + src/Graphic3d/Graphic3d.cdl | 1 + .../Graphic3d_BufferType.hxx} | 22 +- src/Graphic3d/Graphic3d_GraphicDriver.cdl | 8 +- src/Image/FILES | 10 +- src/Image/Image.cdl | 19 +- src/Image/Image_AlienPixMap.cxx | 516 +++++++++++++ src/Image/Image_AlienPixMap.hxx | 96 +++ src/Image/Image_CRawBufferData.hxx | 30 - src/Image/Image_Color.hxx | 543 ++++++++++++++ src/Image/Image_Diff.cxx | 526 +++++++++++++ src/Image/Image_Diff.hxx | 135 ++++ src/Image/Image_PixMap.cdl | 147 ---- src/Image/Image_PixMap.cxx | 703 +++++++----------- src/Image/Image_PixMap.hxx | 294 ++++++++ src/Image/Image_PixMapData.hxx | 113 +++ src/InterfaceGraphic/FILES | 1 - .../InterfaceGraphic_RawBufferData.hxx | 54 -- src/OpenGl/OpenGl_GraphicDriver.hxx | 7 +- src/OpenGl/OpenGl_GraphicDriver_7.cxx | 139 ++-- src/OpenGl/OpenGl_Workspace.hxx | 7 +- src/QADraw/QADraw.cxx | 55 +- src/V3d/V3d_View.cdl | 18 +- src/V3d/V3d_View.cxx | 67 +- src/ViewerTest/ViewerTest.cxx | 26 +- src/ViewerTest/ViewerTest_ViewerCommands.cxx | 123 ++- src/Visual3d/Visual3d_View.cdl | 10 +- src/Visual3d/Visual3d_View.cxx | 5 +- src/WNT/WNT_ImageProcessor.cxx | 77 +- src/WNT/WNT_PixMap.cdl | 11 +- src/WNT/WNT_PixMap.cxx | 29 +- src/WNT/WNT_Window.cdl | 6 +- src/WNT/WNT_Window.cxx | 82 +- src/Xw/Xw_PixMap.cdl | 5 +- src/Xw/Xw_PixMap.cxx | 80 +- src/Xw/Xw_Window.cdl | 6 +- src/Xw/Xw_Window.cxx | 30 +- src/Xw/Xw_save_image.cxx | 31 +- 43 files changed, 3057 insertions(+), 1251 deletions(-) delete mode 100755 src/Aspect/Aspect_PixMap.cdl delete mode 100755 src/Aspect/Aspect_PixMap.cxx rename src/{Image/Image_HPrivateImage.hxx => Graphic3d/Graphic3d_BufferType.hxx} (71%) create mode 100644 src/Image/Image_AlienPixMap.cxx create mode 100644 src/Image/Image_AlienPixMap.hxx delete mode 100644 src/Image/Image_CRawBufferData.hxx create mode 100644 src/Image/Image_Color.hxx create mode 100644 src/Image/Image_Diff.cxx create mode 100644 src/Image/Image_Diff.hxx delete mode 100644 src/Image/Image_PixMap.cdl create mode 100644 src/Image/Image_PixMap.hxx create mode 100644 src/Image/Image_PixMapData.hxx delete mode 100644 src/InterfaceGraphic/InterfaceGraphic_RawBufferData.hxx diff --git a/src/Aspect/Aspect.cdl b/src/Aspect/Aspect.cdl index 509cb073df..39d28919ad 100755 --- a/src/Aspect/Aspect.cdl +++ b/src/Aspect/Aspect.cdl @@ -348,10 +348,6 @@ is deferred class Window; ---Purpose: Defines a window. ---Category: Classes - - deferred class PixMap; - ---Purpose: Defines a pixmap(bitmap) - ---Category: Classes deferred class GraphicDevice; ---Purpose: Defines a physical graphic device allowing to diff --git a/src/Aspect/Aspect_PixMap.cdl b/src/Aspect/Aspect_PixMap.cdl deleted file mode 100755 index a95d3c34c0..0000000000 --- a/src/Aspect/Aspect_PixMap.cdl +++ /dev/null @@ -1,92 +0,0 @@ --- Created on: 1999-10-14 --- Created by: VKH --- Copyright (c) 1999 Matra Datavision --- Copyright (c) 1999-2012 OPEN CASCADE SAS --- --- The content of this file is subject to the Open CASCADE Technology Public --- License Version 6.5 (the "License"). You may not use the content of this file --- except in compliance with the License. Please obtain a copy of the License --- at http://www.opencascade.org and read it completely before using this file. --- --- The Initial Developer of the Original Code is Open CASCADE S.A.S., having its --- main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France. --- --- The Original Code and all software distributed under the License is --- distributed on an "AS IS" basis, without warranty of any kind, and the --- Initial Developer hereby disclaims all such warranties, including without --- limitation, any warranties of merchantability, fitness for a particular --- purpose or non-infringement. Please see the License for the specific terms --- and conditions governing the rights and limitations under the License. - --- Updated: GG IMP100701 Add the "depth" field and method --- to the pixmap object. - - -deferred class PixMap from Aspect -inherits - TShared from MMgt - ---Purpose: This class allows the definition of a pixmap(bitmap) - -uses - Handle from Aspect, - Color from Quantity - -raises - PixmapDefinitionError from Aspect, - PixmapError from Aspect -is - Initialize ( aWidth, anHeight : Integer from Standard; - aDepth : Integer from Standard ); - ---Level: Public - ---Purpose: Initializes the datas of a pixmap with a pixel size - -- , and depth. - - Destroy ( me : mutable ) - raises PixmapError from Aspect is deferred; - ---Level: Advanced - ---Purpose: Destroy the pixmap - ---Category: Methods to modify the class definition - - Dump ( me ; aFilename : CString from Standard; - aGammaValue: Real from Standard = 1.0 ) - returns Boolean - raises PixmapError from Aspect is deferred; - ---Level: Advanced - ---Purpose: - -- Dumps the Bitmap to an image file with - -- an optional gamma correction value - -- and returns TRUE if the dump occurs normaly. - ---Trigger: Raises if pixmap is not defined properly - - PixelColor ( me : in; - theX, theY : in Integer from Standard ) - returns Color from Quantity is deferred; - ---Purpose: - -- Returns the pixel color. - - ---------------------------- - -- Category: Inquire methods - ---------------------------- - - PixmapID ( me ) returns Handle from Aspect - is deferred; - ---Level: Advanced - ---Purpose: Returns the ID of the just created pixmap - ---Category: Inquire methods - - Size ( me ; aWidth, anHeight : out Integer from Standard ) - is static; - ---Level: Public - ---Purpose: Returns the allocated pixmap's size in PIXEL - ---Category: Inquire methods - - Depth ( me ) returns Integer from Standard - is static; - ---Level: Public - ---Purpose: Returns the allocated pixmap's depth (planes number) - ---Category: Inquire methods -fields - myWidth : Integer from Standard is protected; - myHeight : Integer from Standard is protected; - myDepth : Integer from Standard is protected; -end PixMap; diff --git a/src/Aspect/Aspect_PixMap.cxx b/src/Aspect/Aspect_PixMap.cxx deleted file mode 100755 index ea1cd9419d..0000000000 --- a/src/Aspect/Aspect_PixMap.cxx +++ /dev/null @@ -1,52 +0,0 @@ -// Created on: 1999-10-14 -// Created by: VKH -// Copyright (c) 1999 Matra Datavision -// Copyright (c) 1999-2012 OPEN CASCADE SAS -// -// The content of this file is subject to the Open CASCADE Technology Public -// License Version 6.5 (the "License"). You may not use the content of this file -// except in compliance with the License. Please obtain a copy of the License -// at http://www.opencascade.org and read it completely before using this file. -// -// The Initial Developer of the Original Code is Open CASCADE S.A.S., having its -// main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France. -// -// The Original Code and all software distributed under the License is -// distributed on an "AS IS" basis, without warranty of any kind, and the -// Initial Developer hereby disclaims all such warranties, including without -// limitation, any warranties of merchantability, fitness for a particular -// purpose or non-infringement. Please see the License for the specific terms -// and conditions governing the rights and limitations under the License. - - -// Updated GG IMP100701 Add the "depth" field and method -// to the pixmap object. - - -//-Version - -#include - -//-Constructor -//////////////////////////////////////////////////////////////////// -Aspect_PixMap::Aspect_PixMap ( const Standard_Integer aWidth, - const Standard_Integer anHeight, - const Standard_Integer aDepth ) -{ - myWidth = aWidth; - myHeight = anHeight; - myDepth = aDepth; -} - -//////////////////////////////////////////////////////////// -void Aspect_PixMap::Size ( Standard_Integer &aWidth, - Standard_Integer &anHeight ) const { - aWidth = myWidth; - anHeight = myHeight; -} - -//////////////////////////////////////////////////////////// -Standard_Integer Aspect_PixMap::Depth () const { - return myDepth; -} - diff --git a/src/Aspect/Aspect_Window.cdl b/src/Aspect/Aspect_Window.cdl index 859836b070..f939cbddb7 100755 --- a/src/Aspect/Aspect_Window.cdl +++ b/src/Aspect/Aspect_Window.cdl @@ -42,7 +42,6 @@ uses TypeOfResize from Aspect, FillMethod from Aspect, Handle from Aspect, - PixMap from Aspect, Ratio from Quantity, Parameter from Quantity, NameOfColor from Quantity, @@ -208,12 +207,6 @@ is -- or the area is out of the Window. raises WindowError from Aspect is deferred; - ToPixMap ( me ) - returns PixMap from Aspect - ---Level : Public - ---Purpose : dump the full contents of the window to a pixmap. - is deferred; - Load ( me ; aFilename : CString from Standard) returns Boolean ---Level: Advanced ---Purpose: Loads the XWD file to this Window. diff --git a/src/Draw/Draw_Window.cxx b/src/Draw/Draw_Window.cxx index 0a7c0d0060..03a6a78c89 100755 --- a/src/Draw/Draw_Window.cxx +++ b/src/Draw/Draw_Window.cxx @@ -34,7 +34,7 @@ #include #include #include -#include +#include extern Draw_Interpretor theCommands; extern Standard_Boolean Draw_VirtualWindows; @@ -717,38 +717,43 @@ Standard_Boolean Draw_Window::Save (const char* theFileName) const } } - // find the image - XImage* pximage = XGetImage (Draw_WindowDisplay, GetDrawable(), - 0, 0, winAttr.width, winAttr.height, - AllPlanes, ZPixmap); - if (pximage == NULL) + XVisualInfo aVInfo; + if (XMatchVisualInfo (Draw_WindowDisplay, Draw_WindowScreen, 32, TrueColor, &aVInfo) == 0 + && XMatchVisualInfo (Draw_WindowDisplay, Draw_WindowScreen, 24, TrueColor, &aVInfo) == 0) { + std::cerr << "24-bit TrueColor visual is not supported by server!\n"; return Standard_False; } - if (winAttr.visual->c_class == TrueColor) + Image_AlienPixMap anImage; + bool isBigEndian = Image_PixMap::IsBigEndianHost(); + const Standard_Size aSizeRowBytes = Standard_Size(winAttr.width) * 4; + if (!anImage.InitTrash (isBigEndian ? Image_PixMap::ImgRGB32 : Image_PixMap::ImgBGR32, + Standard_Size(winAttr.width), Standard_Size(winAttr.height), aSizeRowBytes)) { - Standard_Byte* aDataPtr = (Standard_Byte* )pximage->data; - Handle(Image_PixMap) anImagePixMap = new Image_PixMap (aDataPtr, - pximage->width, pximage->height, - pximage->bytes_per_line, - pximage->bits_per_pixel, - Standard_True); - // destroy the image - XDestroyImage (pximage); - - // save the image - return anImagePixMap->Dump (theFileName); + return Standard_False; } - else + anImage.SetTopDown (true); + + XImage* anXImage = XCreateImage (Draw_WindowDisplay, aVInfo.visual, + 32, ZPixmap, 0, (char* )anImage.ChangeData(), winAttr.width, winAttr.height, 32, int(aSizeRowBytes)); + anXImage->bitmap_bit_order = anXImage->byte_order = (isBigEndian ? MSBFirst : LSBFirst); + if (XGetSubImage (Draw_WindowDisplay, GetDrawable(), + 0, 0, winAttr.width, winAttr.height, + AllPlanes, ZPixmap, anXImage, 0, 0) == NULL) { - std::cerr << "Visual Type not supported!"; - // destroy the image - XDestroyImage (pximage); + anXImage->data = NULL; + XDestroyImage (anXImage); return Standard_False; } -} + // destroy the image + anXImage->data = NULL; + XDestroyImage (anXImage); + + // save the image + return anImage.Save (theFileName); +} //======================================================================= //function : ProcessEvent @@ -1700,63 +1705,44 @@ void DrawWindow::Clear() /*--------------------------------------------------------*\ | SaveBitmap \*--------------------------------------------------------*/ -static Standard_Boolean SaveBitmap (HBITMAP theHBitmap, +static Standard_Boolean SaveBitmap (HBITMAP theHBitmap, const char* theFileName) { - // Copy data from HBITMAP + // Get informations about the bitmap BITMAP aBitmap; + if (GetObject (theHBitmap, sizeof(BITMAP), (LPSTR )&aBitmap) == 0) + { + return Standard_False; + } - // Get informations about the bitmap - GetObject (theHBitmap, sizeof(BITMAP), (LPSTR )&aBitmap); - Standard_Integer aWidth = aBitmap.bmWidth; - Standard_Integer aHeight = aBitmap.bmHeight; + Image_AlienPixMap anImage; + const Standard_Size aSizeRowBytes = Standard_Size(aBitmap.bmWidth) * 4; + if (!anImage.InitTrash (Image_PixMap::ImgBGR32, Standard_Size(aBitmap.bmWidth), Standard_Size(aBitmap.bmHeight), aSizeRowBytes)) + { + return Standard_False; + } + anImage.SetTopDown (false); // Setup image data BITMAPINFOHEADER aBitmapInfo; memset (&aBitmapInfo, 0, sizeof(BITMAPINFOHEADER)); - aBitmapInfo.biSize = sizeof(BITMAPINFOHEADER); - aBitmapInfo.biWidth = aWidth; - aBitmapInfo.biHeight = aHeight; // positive means bottom-up! - aBitmapInfo.biPlanes = 1; - aBitmapInfo.biBitCount = 32; + aBitmapInfo.biSize = sizeof(BITMAPINFOHEADER); + aBitmapInfo.biWidth = aBitmap.bmWidth; + aBitmapInfo.biHeight = aBitmap.bmHeight; // positive means bottom-up! + aBitmapInfo.biPlanes = 1; + aBitmapInfo.biBitCount = 32; // use 32bit for automatic word-alignment per row aBitmapInfo.biCompression = BI_RGB; - Standard_Integer aBytesPerLine = aWidth * 4; - Standard_Byte* aDataPtr = new Standard_Byte[aBytesPerLine * aHeight]; - // Copy the pixels HDC aDC = GetDC (NULL); - Standard_Boolean isSuccess - = GetDIBits (aDC, // handle to DC - theHBitmap, // handle to bitmap - 0, // first scan line to set - aHeight, // number of scan lines to copy - aDataPtr, // array for bitmap bits - (LPBITMAPINFO )&aBitmapInfo, // bitmap data info - DIB_RGB_COLORS // RGB - ) != 0; - - if (isSuccess) - { - Handle(Image_PixMap) anImagePixMap = new Image_PixMap (aDataPtr, - aWidth, aHeight, - aBytesPerLine, - aBitmapInfo.biBitCount, - Standard_False); // bottom-up! - - // Release dump memory here - delete[] aDataPtr; - - // save the image - anImagePixMap->Dump (theFileName); - } - else - { - // Release dump memory - delete[] aDataPtr; - } + Standard_Boolean isSuccess = GetDIBits (aDC, theHBitmap, + 0, // first scan line to set + aBitmap.bmHeight, // number of scan lines to copy + anImage.ChangeData(), // array for bitmap bits + (LPBITMAPINFO )&aBitmapInfo, // bitmap data info + DIB_RGB_COLORS) != 0; ReleaseDC (NULL, aDC); - return isSuccess; + return isSuccess && anImage.Save (theFileName); } /*--------------------------------------------------------*\ diff --git a/src/Graphic3d/FILES b/src/Graphic3d/FILES index b985933610..e095fa23d5 100755 --- a/src/Graphic3d/FILES +++ b/src/Graphic3d/FILES @@ -53,3 +53,4 @@ Graphic3d_AspectText3d.cxx Graphic3d_WNTGraphicDevice.cxx Graphic3d_NameOfFont.hxx Graphic3d_PtrFrameBuffer.hxx +Graphic3d_BufferType.hxx diff --git a/src/Graphic3d/Graphic3d.cdl b/src/Graphic3d/Graphic3d.cdl index 843f369c4a..03e54b6d83 100755 --- a/src/Graphic3d/Graphic3d.cdl +++ b/src/Graphic3d/Graphic3d.cdl @@ -329,6 +329,7 @@ is --------------------------- imported PrimitiveArray; + imported BufferType; imported CBitFields20; ---Purpose: Defines the C structure diff --git a/src/Image/Image_HPrivateImage.hxx b/src/Graphic3d/Graphic3d_BufferType.hxx similarity index 71% rename from src/Image/Image_HPrivateImage.hxx rename to src/Graphic3d/Graphic3d_BufferType.hxx index 702f83dc07..40c225cc47 100644 --- a/src/Image/Image_HPrivateImage.hxx +++ b/src/Graphic3d/Graphic3d_BufferType.hxx @@ -1,4 +1,4 @@ -// Copyright (c) 1999-2012 OPEN CASCADE SAS +// Copyright (c) 2012 OPEN CASCADE SAS // // The content of this file is subject to the Open CASCADE Technology Public // License Version 6.5 (the "License"). You may not use the content of this file @@ -15,15 +15,15 @@ // purpose or non-infringement. Please see the License for the specific terms // and conditions governing the rights and limitations under the License. -#ifndef _Image_HPrivateImage_HeaderFile -#define _Image_HPrivateImage_HeaderFile +#ifndef _Graphic3d_BufferType_H__ +#define _Graphic3d_BufferType_H__ -#include +//! Define buffers available for dump +typedef enum +{ + Graphic3d_BT_RGB, //!< color buffer without alpha component + Graphic3d_BT_RGBA, //!< color buffer + Graphic3d_BT_Depth //!< depth buffer +} Graphic3d_BufferType; -// This typedef shadows the private image storage class -// Currently FreeImagePlus is used - -class fipImage; -typedef NCollection_Handle Image_HPrivateImage; - -#endif /*_Image_HPrivateImage_HeaderFile*/ +#endif // _Graphic3d_BufferType_H__ diff --git a/src/Graphic3d/Graphic3d_GraphicDriver.cdl b/src/Graphic3d/Graphic3d_GraphicDriver.cdl index 7d5cf4ac90..446ab365de 100755 --- a/src/Graphic3d/Graphic3d_GraphicDriver.cdl +++ b/src/Graphic3d/Graphic3d_GraphicDriver.cdl @@ -71,6 +71,7 @@ uses PlaneAngle from Quantity, AlienImage from AlienImage, + PixMap from Image, Array1OfEdge from Aspect, CLayer2d from Aspect, @@ -93,7 +94,7 @@ uses CPlane from Graphic3d, CStructure from Graphic3d, CView from Graphic3d, - CRawBufferData from Image, + BufferType from Graphic3d, Structure from Graphic3d, TextPath from Graphic3d, TypeOfComposition from Graphic3d, @@ -1008,8 +1009,9 @@ is ---Purpose: Change offscreen FBO viewport. BufferDump( me : mutable; - view : CView from Graphic3d; - buffer : in out CRawBufferData from Image ) + theCView : CView from Graphic3d; + theImage : in out PixMap from Image; + theBufferType : BufferType from Graphic3d ) returns Boolean from Standard is deferred; ---Purpose: Dump active rendering buffer into specified memory buffer. diff --git a/src/Image/FILES b/src/Image/FILES index 5b70dabe66..84ca817506 100755 --- a/src/Image/FILES +++ b/src/Image/FILES @@ -6,5 +6,11 @@ Image_PixelAddress.cxx Image_PixelAddress.hxx Image.edl Image_CMPLRS.edl -Image_CRawBufferData.hxx -Image_HPrivateImage.hxx +Image_PixMap.hxx +Image_PixMap.cxx +Image_PixMapData.hxx +Image_Color.hxx +Image_AlienPixMap.hxx +Image_AlienPixMap.cxx +Image_Diff.hxx +Image_Diff.cxx diff --git a/src/Image/Image.cdl b/src/Image/Image.cdl index 5be5645450..a34e05e152 100755 --- a/src/Image/Image.cdl +++ b/src/Image/Image.cdl @@ -88,18 +88,16 @@ is IndexPixel from Aspect, IndexPixelMapHasher ); - class PixMap; - ---Purpose: Aspect_PixMap implementation. - ----------------------------- ---Category: Imported types: ----------------------------- imported PixelAddress; - - imported HPrivateImage; - - imported CRawBufferData; + imported PixMap; + imported AlienPixMap; + imported PixMap_Handle; + imported AlienPixMap_Handle; + imported Diff; ----------------------------- ---Category: The Enumerations @@ -132,12 +130,7 @@ is ---Purpose: Type of dithering method. enumeration TypeOfImage is TOI_ColorImage, - TOI_PseudoColorImage, - TOI_RGB, - TOI_RGBA, - TOI_RGBF, - TOI_RGBAF, - TOI_FLOAT + TOI_PseudoColorImage end TypeOfImage ; Zoom ( aImage : mutable Image from Image ; diff --git a/src/Image/Image_AlienPixMap.cxx b/src/Image/Image_AlienPixMap.cxx new file mode 100644 index 0000000000..ee5d5cb87a --- /dev/null +++ b/src/Image/Image_AlienPixMap.cxx @@ -0,0 +1,516 @@ +// Created on: 2010-09-16 +// Created by: KGV +// Copyright (c) 2010-2012 OPEN CASCADE SAS +// +// The content of this file is subject to the Open CASCADE Technology Public +// License Version 6.5 (the "License"). You may not use the content of this file +// except in compliance with the License. Please obtain a copy of the License +// at http://www.opencascade.org and read it completely before using this file. +// +// The Initial Developer of the Original Code is Open CASCADE S.A.S., having its +// main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France. +// +// The Original Code and all software distributed under the License is +// distributed on an "AS IS" basis, without warranty of any kind, and the +// Initial Developer hereby disclaims all such warranties, including without +// limitation, any warranties of merchantability, fitness for a particular +// purpose or non-infringement. Please see the License for the specific terms +// and conditions governing the rights and limitations under the License. + +#ifdef HAVE_CONFIG_H + #include +#endif + +#ifdef HAVE_FREEIMAGE + #include + + #ifdef _MSC_VER + #pragma comment( lib, "FreeImage.lib" ) + #endif +#endif + +#include +#include +#include +#include + +#ifdef HAVE_FREEIMAGE +namespace +{ + static Image_PixMap::ImgFormat convertFromFreeFormat (FREE_IMAGE_TYPE theFormatFI, + FREE_IMAGE_COLOR_TYPE theColorTypeFI, + unsigned theBitsPerPixel) + { + switch (theFormatFI) + { + case FIT_RGBF: return Image_PixMap::ImgRGBF; + case FIT_RGBAF: return Image_PixMap::ImgRGBAF; + case FIT_FLOAT: return Image_PixMap::ImgGrayF; + case FIT_BITMAP: + { + switch (theColorTypeFI) + { + case FIC_MINISBLACK: + { + return Image_PixMap::ImgGray; + } + case FIC_RGB: + { + if (Image_PixMap::IsBigEndianHost()) + { + return (theBitsPerPixel == 32) ? Image_PixMap::ImgRGB32 : Image_PixMap::ImgRGB; + } + else + { + return (theBitsPerPixel == 32) ? Image_PixMap::ImgBGR32 : Image_PixMap::ImgBGR; + } + } + case FIC_RGBALPHA: + { + return Image_PixMap::IsBigEndianHost() ? Image_PixMap::ImgRGBA : Image_PixMap::ImgBGRA; + } + default: + return Image_PixMap::ImgUNKNOWN; + } + } + default: + return Image_PixMap::ImgUNKNOWN; + } + } + + static FREE_IMAGE_TYPE convertToFreeFormat (Image_PixMap::ImgFormat theFormat) + { + switch (theFormat) + { + case Image_PixMap::ImgGrayF: + return FIT_FLOAT; + case Image_PixMap::ImgRGBAF: + return FIT_RGBAF; + case Image_PixMap::ImgRGBF: + return FIT_RGBF; + case Image_PixMap::ImgRGBA: + case Image_PixMap::ImgBGRA: + case Image_PixMap::ImgRGB32: + case Image_PixMap::ImgBGR32: + case Image_PixMap::ImgRGB: + case Image_PixMap::ImgBGR: + case Image_PixMap::ImgGray: + return FIT_BITMAP; + default: + return FIT_UNKNOWN; + } + } +}; +#endif + +IMPLEMENT_STANDARD_HANDLE (Image_AlienPixMap, Image_PixMap) +IMPLEMENT_STANDARD_RTTIEXT(Image_AlienPixMap, Image_PixMap) + +// ======================================================================= +// function : Image_AlienPixMap +// purpose : +// ======================================================================= +Image_AlienPixMap::Image_AlienPixMap() +: myLibImage (NULL) +{ + SetTopDown (false); +} + +// ======================================================================= +// function : ~Image_AlienPixMap +// purpose : +// ======================================================================= +Image_AlienPixMap::~Image_AlienPixMap() +{ + Clear(); +} + +// ======================================================================= +// function : InitWrapper +// purpose : +// ======================================================================= +bool Image_AlienPixMap::InitWrapper (ImgFormat thePixelFormat, + Standard_Byte* theDataPtr, + const Standard_Size theSizeX, + const Standard_Size theSizeY, + const Standard_Size theSizeRowBytes) +{ + Clear(); + return false; +} + +// ======================================================================= +// function : InitTrash +// purpose : +// ======================================================================= +bool Image_AlienPixMap::InitTrash (ImgFormat thePixelFormat, + const Standard_Size theSizeX, + const Standard_Size theSizeY, + const Standard_Size theSizeRowBytes) +{ + Clear(); +#ifdef HAVE_FREEIMAGE + FREE_IMAGE_TYPE aFormatFI = convertToFreeFormat (thePixelFormat); + int aBitsPerPixel = (int )Image_PixMap::SizePixelBytes (thePixelFormat) * 8; + if (aFormatFI == FIT_UNKNOWN) + { + aFormatFI = FIT_BITMAP; + aBitsPerPixel = 24; + } + + FIBITMAP* anImage = FreeImage_AllocateT (aFormatFI, (int )theSizeX, (int )theSizeY, aBitsPerPixel); + Image_PixMap::ImgFormat aFormat = convertFromFreeFormat (FreeImage_GetImageType (anImage), + FreeImage_GetColorType (anImage), + FreeImage_GetBPP (anImage)); + if (thePixelFormat == Image_PixMap::ImgBGR32 + || thePixelFormat == Image_PixMap::ImgRGB32) + { + //FreeImage_SetTransparent (anImage, FALSE); + aFormat = (aFormat == Image_PixMap::ImgBGRA) ? Image_PixMap::ImgBGR32 : Image_PixMap::ImgRGB32; + } + + Image_PixMap::InitWrapper (aFormat, FreeImage_GetBits (anImage), + FreeImage_GetWidth (anImage), FreeImage_GetHeight (anImage), FreeImage_GetPitch (anImage)); + SetTopDown (false); + + // assign image after wrapper initialization (virtual Clear() called inside) + myLibImage = anImage; + return true; +#else + return Image_PixMap::InitTrash (thePixelFormat, theSizeX, theSizeY, theSizeRowBytes); +#endif +} + +// ======================================================================= +// function : Clear +// purpose : +// ======================================================================= +bool Image_AlienPixMap::InitCopy (const Image_PixMap& theCopy) +{ + if (&theCopy == this) + { + // self-copying disallowed + return false; + } + if (!InitTrash (theCopy.Format(), theCopy.SizeX(), theCopy.SizeY(), theCopy.SizeRowBytes())) + { + return false; + } + + if (myImgFormat == theCopy.Format()) + { + if (myData.mySizeRowBytes == theCopy.SizeRowBytes() + && myData.myTopToDown == theCopy.TopDownInc()) + { + // copy with one call + memcpy (myData.myDataPtr, theCopy.Data(), theCopy.SizeBytes()); + return true; + } + + // copy row-by-row + const Standard_Size aRowSizeBytes = (myData.mySizeRowBytes > theCopy.SizeRowBytes()) + ? theCopy.SizeRowBytes() : myData.mySizeRowBytes; + for (Standard_Size aRow = 0; aRow < myData.mySizeY; ++aRow) + { + memcpy (ChangeRow (aRow), theCopy.Row (aRow), aRowSizeBytes); + } + return true; + } + + // pixel format conversion required + Clear(); + return false; +} + +// ======================================================================= +// function : Clear +// purpose : +// ======================================================================= +void Image_AlienPixMap::Clear (ImgFormat thePixelFormat) +{ + Image_PixMap::Clear (thePixelFormat); +#ifdef HAVE_FREEIMAGE + if (myLibImage != NULL) + { + FreeImage_Unload (myLibImage); + myLibImage = NULL; + } +#endif +} + +// ======================================================================= +// function : Load +// purpose : +// ======================================================================= +bool Image_AlienPixMap::Load (const TCollection_AsciiString& theImagePath) +{ + Clear(); +#ifdef HAVE_FREEIMAGE + + FREE_IMAGE_FORMAT aFIF = FreeImage_GetFileType (theImagePath.ToCString(), 0); + if (aFIF == FIF_UNKNOWN) + { + // no signature? try to guess the file format from the file extension + aFIF = FreeImage_GetFIFFromFilename (theImagePath.ToCString()); + } + if ((aFIF == FIF_UNKNOWN) || !FreeImage_FIFSupportsReading (aFIF)) + { + // unsupported image format + return false; + } + + int aLoadFlags = 0; + if (aFIF == FIF_GIF) + { + // 'Play' the GIF to generate each frame (as 32bpp) instead of returning raw frame data when loading + aLoadFlags = GIF_PLAYBACK; + } + else if (aFIF == FIF_ICO) + { + // convert to 32bpp and create an alpha channel from the AND-mask when loading + aLoadFlags = ICO_MAKEALPHA; + } + + FIBITMAP* anImage = FreeImage_Load (aFIF, theImagePath.ToCString(), aLoadFlags); + if (anImage == NULL) + { + return false; + } + + Image_PixMap::ImgFormat aFormat = convertFromFreeFormat (FreeImage_GetImageType (anImage), + FreeImage_GetColorType (anImage), + FreeImage_GetBPP (anImage)); + if (aFormat == Image_PixMap::ImgUNKNOWN) + { + //anImage = FreeImage_ConvertTo24Bits (anImage); + return false; + } + + Image_PixMap::InitWrapper (aFormat, FreeImage_GetBits (anImage), + FreeImage_GetWidth (anImage), FreeImage_GetHeight (anImage), FreeImage_GetPitch (anImage)); + SetTopDown (false); + + // assign image after wrapper initialization (virtual Clear() called inside) + myLibImage = anImage; + return true; +#else + return false; +#endif +} + +// ======================================================================= +// function : savePPM +// purpose : +// ======================================================================= +bool Image_AlienPixMap::savePPM (const TCollection_AsciiString& theFileName) const +{ + if (IsEmpty()) + { + return false; + } + + // Open file + FILE* aFile = fopen (theFileName.ToCString(), "wb"); + if (aFile == NULL) + { + return false; + } + + // Write header + fprintf (aFile, "P6\n%d %d\n255\n", (int )SizeX(), (int )SizeY()); + fprintf (aFile, "# Image stored by OpenCASCADE framework in linear RGB colorspace\n"); + + // Write pixel data + Quantity_Color aColor; + Quantity_Parameter aDummy; + Standard_Byte aByte; + for (Standard_Size aRow = 0; aRow < SizeY(); ++aRow) + { + for (Standard_Size aCol = 0; aCol < SizeY(); ++aCol) + { + // extremely SLOW but universal (implemented for all supported pixel formats) + aColor = PixelColor (aCol, aRow, aDummy); + aByte = Standard_Byte(aColor.Red() * 255.0); fwrite (&aByte, 1, 1, aFile); + aByte = Standard_Byte(aColor.Green() * 255.0); fwrite (&aByte, 1, 1, aFile); + aByte = Standard_Byte(aColor.Blue() * 255.0); fwrite (&aByte, 1, 1, aFile); + } + } + + // Close file + fclose (aFile); + return true; +} + +// ======================================================================= +// function : Save +// purpose : +// ======================================================================= +bool Image_AlienPixMap::Save (const TCollection_AsciiString& theFileName) +{ +#ifdef HAVE_FREEIMAGE + if (myLibImage == NULL) + { + return false; + } + + FREE_IMAGE_FORMAT anImageFormat = FreeImage_GetFIFFromFilename (theFileName.ToCString()); + if (anImageFormat == FIF_UNKNOWN) + { + std::cerr << "Image_PixMap, image format doesn't supported!\n"; + return false; + } + + if (IsTopDown()) + { + FreeImage_FlipVertical (myLibImage); + SetTopDown (false); + } + + // FreeImage doesn't provide flexible format convertion API + // so we should perform multiple convertions in some cases! + Standard_Boolean isCopied = Standard_False; + FIBITMAP* anImageToDump = myLibImage; + switch (anImageFormat) + { + case FIF_PNG: + case FIF_BMP: + { + if (Format() == Image_PixMap::ImgBGR32 + || Format() == Image_PixMap::ImgRGB32) + { + // stupid FreeImage treats reserved byte as alpha if some bytes not set to 0xFF + Image_PixMapData& aData = Image_PixMap::EditData(); + for (Standard_Size aRow = 0; aRow < SizeY(); ++aRow) + { + for (Standard_Size aCol = 0; aCol < SizeX(); ++aCol) + { + aData.ChangeValue (aRow, aCol).a_() = 0xFF; + } + } + } + else if (FreeImage_GetImageType (myLibImage) != FIT_BITMAP) + { + anImageToDump = FreeImage_ConvertToType (myLibImage, FIT_BITMAP); + } + break; + } + case FIF_GIF: + { + FIBITMAP* aTmpBitmap = myLibImage; + if (FreeImage_GetImageType (myLibImage) != FIT_BITMAP) + { + aTmpBitmap = FreeImage_ConvertToType (myLibImage, FIT_BITMAP); + if (aTmpBitmap == NULL) + { + return false; + } + } + + if (FreeImage_GetBPP (aTmpBitmap) != 24) + { + FIBITMAP* aTmpBitmap24 = FreeImage_ConvertTo24Bits (aTmpBitmap); + if (aTmpBitmap != myLibImage) + { + FreeImage_Unload (aTmpBitmap); + } + if (aTmpBitmap24 == NULL) + { + return false; + } + aTmpBitmap = aTmpBitmap24; + } + + // need convertion to image with pallete (requires 24bit bitmap) + anImageToDump = FreeImage_ColorQuantize (aTmpBitmap, FIQ_NNQUANT); + if (aTmpBitmap != myLibImage) + { + FreeImage_Unload (aTmpBitmap); + } + break; + } + case FIF_EXR: + { + if (Format() == Image_PixMap::ImgGray) + { + anImageToDump = FreeImage_ConvertToType (myLibImage, FIT_FLOAT); + } + else if (Format() == Image_PixMap::ImgRGBA + || Format() == Image_PixMap::ImgBGRA) + { + anImageToDump = FreeImage_ConvertToType (myLibImage, FIT_RGBAF); + } + else + { + FREE_IMAGE_TYPE aImgTypeFI = FreeImage_GetImageType (myLibImage); + if (aImgTypeFI != FIT_RGBF + && aImgTypeFI != FIT_RGBAF + && aImgTypeFI != FIT_FLOAT) + { + anImageToDump = FreeImage_ConvertToType (myLibImage, FIT_RGBF); + } + } + break; + } + default: + { + if (FreeImage_GetImageType (myLibImage) != FIT_BITMAP) + { + anImageToDump = FreeImage_ConvertToType (myLibImage, FIT_BITMAP); + if (anImageToDump == NULL) + { + return false; + } + } + + if (FreeImage_GetBPP (anImageToDump) != 24) + { + FIBITMAP* aTmpBitmap24 = FreeImage_ConvertTo24Bits (anImageToDump); + if (anImageToDump != myLibImage) + { + FreeImage_Unload (anImageToDump); + } + if (aTmpBitmap24 == NULL) + { + return false; + } + anImageToDump = aTmpBitmap24; + } + break; + } + } + + if (anImageToDump == NULL) + { + return false; + } + + bool isSaved = (FreeImage_Save (anImageFormat, anImageToDump, theFileName.ToCString()) != FALSE); + if (anImageToDump != myLibImage) + { + FreeImage_Unload (anImageToDump); + } + return isSaved; +#else + const Standard_Integer aLen = theFileName.Length(); + if ((aLen >= 4) && (theFileName.Value (aLen - 3) == '.') + && TCollection_AsciiString::ISSIMILAR (theFileName.SubString (aLen - 2, aLen), "ppm")) + { + return savePPM (theFileName); + } + std::cerr << "Image_PixMap, no image library available! Image saved in PPM format.\n"; + return savePPM (theFileName); +#endif +} + +// ======================================================================= +// function : AdjustGamma +// purpose : +// ======================================================================= +Standard_EXPORT bool Image_AlienPixMap::AdjustGamma (const Standard_Real theGammaCorr) +{ +#ifdef HAVE_FREEIMAGE + return FreeImage_AdjustGamma (myLibImage, theGammaCorr) != FALSE; +#else + return false; +#endif +} diff --git a/src/Image/Image_AlienPixMap.hxx b/src/Image/Image_AlienPixMap.hxx new file mode 100644 index 0000000000..85045b2705 --- /dev/null +++ b/src/Image/Image_AlienPixMap.hxx @@ -0,0 +1,96 @@ +// Created on: 2012-07-18 +// Created by: Kirill GAVRILOV +// Copyright (c) 2012 OPEN CASCADE SAS +// +// The content of this file is subject to the Open CASCADE Technology Public +// License Version 6.5 (the "License"). You may not use the content of this file +// except in compliance with the License. Please obtain a copy of the License +// at http://www.opencascade.org and read it completely before using this file. +// +// The Initial Developer of the Original Code is Open CASCADE S.A.S., having its +// main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France. +// +// The Original Code and all software distributed under the License is +// distributed on an "AS IS" basis, without warranty of any kind, and the +// Initial Developer hereby disclaims all such warranties, including without +// limitation, any warranties of merchantability, fitness for a particular +// purpose or non-infringement. Please see the License for the specific terms +// and conditions governing the rights and limitations under the License. + +#ifndef _Image_AlienPixMap_H__ +#define _Image_AlienPixMap_H__ + +#include +#include + +class TCollection_AsciiString; +struct FIBITMAP; + +//! Image class that support file reading/writing operations using auxiliary image library. +//! Notice that supported images format could be limited. +class Image_AlienPixMap : public Image_PixMap +{ + +public: + + //! Empty constructor. + Standard_EXPORT Image_AlienPixMap(); + + //! Destructor + Standard_EXPORT virtual ~Image_AlienPixMap(); + + //! Read image data from file. + Standard_EXPORT bool Load (const TCollection_AsciiString& theFileName); + + //! Write image data to file using file extension to determine compression format. + Standard_EXPORT bool Save (const TCollection_AsciiString& theFileName); + + //! Initialize image plane with required dimensions. + //! thePixelFormat - if specified pixel format doesn't supported by image library + //! than nearest supported will be used instead! + //! theSizeRowBytes - may be ignored by this class and required alignemnt will be used instead! + Standard_EXPORT virtual bool InitTrash (ImgFormat thePixelFormat, + const Standard_Size theSizeX, + const Standard_Size theSizeY, + const Standard_Size theSizeRowBytes = 0); + + //! Initialize by copying data. + Standard_EXPORT virtual bool InitCopy (const Image_PixMap& theCopy); + + //! Method correctly deallocate internal buffer. + Standard_EXPORT virtual void Clear (ImgFormat thePixelFormat = ImgGray); + + //! Performs gamma correction on image. + //! theGamma - gamma value to use; a value of 1.0 leaves the image alone + Standard_EXPORT bool AdjustGamma (const Standard_Real theGammaCorr); + +private: + + FIBITMAP* myLibImage; + +private: + + //! Copying allowed only within Handles + Image_AlienPixMap (const Image_AlienPixMap& ); + Image_AlienPixMap& operator= (const Image_AlienPixMap& ); + + //! Wrapper initialization is disallowed for this class (will return false in any case)! + //! Use only copying and allocation initializers. + Standard_EXPORT virtual bool InitWrapper (ImgFormat thePixelFormat, + Standard_Byte* theDataPtr, + const Standard_Size theSizeX, + const Standard_Size theSizeY, + const Standard_Size theSizeRowBytes); + + //! Built-in PPM export + Standard_EXPORT bool savePPM (const TCollection_AsciiString& theFileName) const; + +public: + + DEFINE_STANDARD_RTTI(Image_AlienPixMap) // Type definition + +}; + +DEFINE_STANDARD_HANDLE(Image_AlienPixMap, Image_PixMap) + +#endif // _Image_AlienPixMap_H__ diff --git a/src/Image/Image_CRawBufferData.hxx b/src/Image/Image_CRawBufferData.hxx deleted file mode 100644 index 48c137a142..0000000000 --- a/src/Image/Image_CRawBufferData.hxx +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) 1999-2012 OPEN CASCADE SAS -// -// The content of this file is subject to the Open CASCADE Technology Public -// License Version 6.5 (the "License"). You may not use the content of this file -// except in compliance with the License. Please obtain a copy of the License -// at http://www.opencascade.org and read it completely before using this file. -// -// The Initial Developer of the Original Code is Open CASCADE S.A.S., having its -// main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France. -// -// The Original Code and all software distributed under the License is -// distributed on an "AS IS" basis, without warranty of any kind, and the -// Initial Developer hereby disclaims all such warranties, including without -// limitation, any warranties of merchantability, fitness for a particular -// purpose or non-infringement. Please see the License for the specific terms -// and conditions governing the rights and limitations under the License. - -#ifndef _Image_CRawBufferData_HeaderFile -#define _Image_CRawBufferData_HeaderFile - -#include - -typedef TRawBufferData Image_CRawBufferData; - -#if defined(__cplusplus) || defined(c_plusplus) - #include - const Handle(Standard_Type)& TYPE(Image_CRawBufferData); -#endif - -#endif /*_Image_CRawBufferData_HeaderFile*/ diff --git a/src/Image/Image_Color.hxx b/src/Image/Image_Color.hxx new file mode 100644 index 0000000000..ef58a57676 --- /dev/null +++ b/src/Image/Image_Color.hxx @@ -0,0 +1,543 @@ +// Created on: 2012-07-18 +// Created by: Kirill GAVRILOV +// Copyright (c) 2012 OPEN CASCADE SAS +// +// The content of this file is subject to the Open CASCADE Technology Public +// License Version 6.5 (the "License"). You may not use the content of this file +// except in compliance with the License. Please obtain a copy of the License +// at http://www.opencascade.org and read it completely before using this file. +// +// The Initial Developer of the Original Code is Open CASCADE S.A.S., having its +// main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France. +// +// The Original Code and all software distributed under the License is +// distributed on an "AS IS" basis, without warranty of any kind, and the +// Initial Developer hereby disclaims all such warranties, including without +// limitation, any warranties of merchantability, fitness for a particular +// purpose or non-infringement. Please see the License for the specific terms +// and conditions governing the rights and limitations under the License. + +#ifndef _Image_Color_H__ +#define _Image_Color_H__ + +#include + +//! POD structure for packed RGB color value (3 bytes) +struct Image_ColorRGB +{ + + //! Returns the number of components. + static Standard_Integer Length() + { + return 3; + } + +public: // access methods + + //! Alias to 1st component (red intensity). + Standard_Byte r() const { return v[0]; } + + //! Alias to 2nd component (green intensity). + Standard_Byte g() const { return v[1]; } + + //! Alias to 3rd component (blue intensity). + Standard_Byte b() const { return v[2]; } + + //! Alias to 1st component (red intensity). + Standard_Byte& r() { return v[0]; } + + //! Alias to 2nd component (green intensity). + Standard_Byte& g() { return v[1]; } + + //! Alias to 3rd component (blue intensity). + Standard_Byte& b() { return v[2]; } + +public: + + Standard_Byte v[3]; + +}; + +//! POD structure for packed RGB color value (4 bytes with extra byte for alignment) +struct Image_ColorRGB32 +{ + + //! Returns the number of components. + static Standard_Integer Length() + { + return 3; + } + + //! Alias to 1st component (red intensity). + Standard_Byte r() const { return v[0]; } + + //! Alias to 2nd component (green intensity). + Standard_Byte g() const { return v[1]; } + + //! Alias to 3rd component (blue intensity). + Standard_Byte b() const { return v[2]; } + + //! Alias to 4th component (dummy). + Standard_Byte a_() const { return v[3]; } + + //! Alias to 1st component (red intensity). + Standard_Byte& r() { return v[0]; } + + //! Alias to 2nd component (green intensity). + Standard_Byte& g() { return v[1]; } + + //! Alias to 3rd component (blue intensity). + Standard_Byte& b() { return v[2]; } + + //! Alias to 4th component (dummy). + Standard_Byte& a_() { return v[3]; } + +public: + + Standard_Byte v[4]; + +}; + +//! POD structure for packed RGBA color value (4 bytes) +struct Image_ColorRGBA +{ + + //! Returns the number of components. + static Standard_Integer Length() + { + return 4; + } + + //! Alias to 1st component (red intensity). + Standard_Byte r() const { return v[0]; } + + //! Alias to 2nd component (green intensity). + Standard_Byte g() const { return v[1]; } + + //! Alias to 3rd component (blue intensity). + Standard_Byte b() const { return v[2]; } + + //! Alias to 4th component (alpha value). + Standard_Byte a() const { return v[3]; } + + //! Alias to 1st component (red intensity). + Standard_Byte& r() { return v[0]; } + + //! Alias to 2nd component (green intensity). + Standard_Byte& g() { return v[1]; } + + //! Alias to 3rd component (blue intensity). + Standard_Byte& b() { return v[2]; } + + //! Alias to 4th component (alpha value). + Standard_Byte& a() { return v[3]; } + +public: + + Standard_Byte v[4]; + +}; + +//! POD structure for packed BGR color value (3 bytes) +struct Image_ColorBGR +{ + + //! Returns the number of components. + static Standard_Integer Length() + { + return 3; + } + + //! Alias to 3rd component (red intensity). + Standard_Byte r() const { return v[2]; } + + //! Alias to 2nd component (green intensity). + Standard_Byte g() const { return v[1]; } + + //! Alias to 1st component (blue intensity). + Standard_Byte b() const { return v[0]; } + + //! Alias to 3rd component (red intensity). + Standard_Byte& r() { return v[2]; } + + //! Alias to 2nd component (green intensity). + Standard_Byte& g() { return v[1]; } + + //! Alias to 1st component (blue intensity). + Standard_Byte& b() { return v[0]; } + +public: + + Standard_Byte v[3]; + +}; + +//! POD structure for packed BGR color value (4 bytes with extra byte for alignment) +struct Image_ColorBGR32 +{ + + //! Returns the number of components. + static Standard_Integer Length() + { + return 3; + } + + //! Alias to 3rd component (red intensity). + Standard_Byte r() const { return v[2]; } + + //! Alias to 2nd component (green intensity). + Standard_Byte g() const { return v[1]; } + + //! Alias to 1st component (blue intensity). + Standard_Byte b() const { return v[0]; } + + //! Alias to 4th component (dummy). + Standard_Byte a_() const { return v[3]; } + + //! Alias to 3rd component (red intensity). + Standard_Byte& r() { return v[2]; } + + //! Alias to 2nd component (green intensity). + Standard_Byte& g() { return v[1]; } + + //! Alias to 1st component (blue intensity). + Standard_Byte& b() { return v[0]; } + + //! Alias to 4th component (dummy). + Standard_Byte& a_() { return v[3]; } + +public: + + Standard_Byte v[4]; + +}; + +//! POD structure for packed BGRA color value (4 bytes) +struct Image_ColorBGRA +{ + + //! Returns the number of components. + static Standard_Integer Length() + { + return 4; + } + + //! Alias to 3rd component (red intensity). + Standard_Byte r() const { return v[2]; } + + //! Alias to 2nd component (green intensity). + Standard_Byte g() const { return v[1]; } + + //! Alias to 1st component (blue intensity). + Standard_Byte b() const { return v[0]; } + + //! Alias to 4th component (alpha value). + Standard_Byte a() const { return v[3]; } + + //! Alias to 3rd component (red intensity). + Standard_Byte& r() { return v[2]; } + + //! Alias to 2nd component (green intensity). + Standard_Byte& g() { return v[1]; } + + //! Alias to 1st component (blue intensity). + Standard_Byte& b() { return v[0]; } + + //! Alias to 4th component (alpha value). + Standard_Byte& a() { return v[3]; } + +public: + + Standard_Byte v[4]; + +}; + +//! POD structure for packed float RGB color value (3 floats) +struct Image_ColorRGBF +{ + + //! Returns the number of components. + static Standard_Integer Length() + { + return 3; + } + + //! Alias to 1st component (red intensity). + Standard_ShortReal r() const { return v[0]; } + + //! Alias to 2nd component (green intensity). + Standard_ShortReal g() const { return v[1]; } + + //! Alias to 3rd component (blue intensity). + Standard_ShortReal b() const { return v[2]; } + + //! Alias to 1st component (red intensity). + Standard_ShortReal& r() { return v[0]; } + + //! Alias to 2nd component (green intensity). + Standard_ShortReal& g() { return v[1]; } + + //! Alias to 3rd component (blue intensity). + Standard_ShortReal& b() { return v[2]; } + +public: + + Standard_ShortReal v[3]; + +}; + +//! POD structure for packed BGR float color value (3 floats) +struct Image_ColorBGRF +{ + + //! Returns the number of components. + static Standard_Integer Length() + { + return 3; + } + + //! Alias to 3rd component (red intensity). + Standard_ShortReal r() const { return v[2]; } + + //! Alias to 2nd component (green intensity). + Standard_ShortReal g() const { return v[1]; } + + //! Alias to 1st component (blue intensity). + Standard_ShortReal b() const { return v[0]; } + + //! Alias to 3rd component (red intensity). + Standard_ShortReal& r() { return v[2]; } + + //! Alias to 2nd component (green intensity). + Standard_ShortReal& g() { return v[1]; } + + //! Alias to 1st component (blue intensity). + Standard_ShortReal& b() { return v[0]; } + +public: + + Standard_ShortReal v[3]; + +}; + +//! POD structure for packed RGBA color value (4 floats) +struct Image_ColorRGBAF +{ + + //! Returns the number of components. + static Standard_Integer Length() + { + return 4; + } + + //! Alias to 1st component (red intensity). + Standard_ShortReal r() const { return v[0]; } + + //! Alias to 2nd component (green intensity). + Standard_ShortReal g() const { return v[1]; } + + //! Alias to 3rd component (blue intensity). + Standard_ShortReal b() const { return v[2]; } + + //! Alias to 4th component (alpha value). + Standard_ShortReal a() const { return v[3]; } + + //! Alias to 1st component (red intensity). + Standard_ShortReal& r() { return v[0]; } + + //! Alias to 2nd component (green intensity). + Standard_ShortReal& g() { return v[1]; } + + //! Alias to 3rd component (blue intensity). + Standard_ShortReal& b() { return v[2]; } + + //! Alias to 4th component (alpha value). + Standard_ShortReal& a() { return v[3]; } + +public: + + Standard_ShortReal v[4]; + +}; + +//! POD structure for packed float BGRA color value (4 floats) +struct Image_ColorBGRAF +{ + + //! Returns the number of components. + static Standard_Integer Length() + { + return 4; + } + + //! Alias to 3rd component (red intensity). + Standard_ShortReal r() const { return v[2]; } + + //! Alias to 2nd component (green intensity). + Standard_ShortReal g() const { return v[1]; } + + //! Alias to 1st component (blue intensity). + Standard_ShortReal b() const { return v[0]; } + + //! Alias to 4th component (alpha value). + Standard_ShortReal a() const { return v[3]; } + + //! Alias to 3rd component (red intensity). + Standard_ShortReal& r() { return v[2]; } + + //! Alias to 2nd component (green intensity). + Standard_ShortReal& g() { return v[1]; } + + //! Alias to 1st component (blue intensity). + Standard_ShortReal& b() { return v[0]; } + + //! Alias to 4th component (alpha value). + Standard_ShortReal& a() { return v[3]; } + +public: + + Standard_ShortReal v[4]; + +}; + +//! Addition operator +template +inline ColorType_t Image_ColorSumm3 (const ColorType_t& theA, const ColorType_t& theB) +{ + ColorType_t aRes = { theA.v[0] + theB.v[0], + theA.v[1] + theB.v[1], + theA.v[2] + theB.v[2] }; + return aRes; +} + +inline Image_ColorRGB operator+ (const Image_ColorRGB& theA, const Image_ColorRGB& theB) +{ + return Image_ColorSumm3 (theA, theB); +} + +inline Image_ColorBGR operator+ (const Image_ColorBGR& theA, const Image_ColorBGR& theB) +{ + return Image_ColorSumm3 (theA, theB); +} + +inline Image_ColorRGBF operator+ (const Image_ColorRGBF& theA, const Image_ColorRGBF& theB) +{ + return Image_ColorSumm3 (theA, theB); +} + +inline Image_ColorBGRF operator+ (const Image_ColorBGRF& theA, const Image_ColorBGRF& theB) +{ + return Image_ColorSumm3 (theA, theB); +} + +template +inline ColorType_t Image_ColorSumm4 (const ColorType_t& theA, const ColorType_t& theB) +{ + ColorType_t aRes = { theA.v[0] + theB.v[0], + theA.v[1] + theB.v[1], + theA.v[2] + theB.v[2], + theA.v[3] + theB.v[3] }; + return aRes; +} + +inline Image_ColorRGBA operator+ (const Image_ColorRGBA& theA, const Image_ColorRGBA& theB) +{ + return Image_ColorSumm4 (theA, theB); +} + +inline Image_ColorBGRA operator+ (const Image_ColorBGRA& theA, const Image_ColorBGRA& theB) +{ + return Image_ColorSumm4 (theA, theB); +} + +inline Image_ColorRGB32 operator+ (const Image_ColorRGB32& theA, const Image_ColorRGB32& theB) +{ + return Image_ColorSumm4 (theA, theB); +} + +inline Image_ColorBGR32 operator+ (const Image_ColorBGR32& theA, const Image_ColorBGR32& theB) +{ + return Image_ColorSumm4 (theA, theB); +} + +inline Image_ColorRGBAF operator+ (const Image_ColorRGBAF& theA, const Image_ColorRGBAF& theB) +{ + return Image_ColorSumm4 (theA, theB); +} + +inline Image_ColorBGRAF operator+ (const Image_ColorBGRAF& theA, const Image_ColorBGRAF& theB) +{ + return Image_ColorSumm4 (theA, theB); +} + +//! Subtraction operator +template +inline ColorType_t Image_ColorSub3 (const ColorType_t& theA, const ColorType_t& theB) +{ + ColorType_t aRes = { theA.v[0] - theB.v[0], + theA.v[1] - theB.v[1], + theA.v[2] - theB.v[2] }; + return aRes; +} + +inline Image_ColorRGB operator- (const Image_ColorRGB& theA, const Image_ColorRGB& theB) +{ + return Image_ColorSub3 (theA, theB); +} + +inline Image_ColorBGR operator- (const Image_ColorBGR& theA, const Image_ColorBGR& theB) +{ + return Image_ColorSub3 (theA, theB); +} + +inline Image_ColorRGBF operator- (const Image_ColorRGBF& theA, const Image_ColorRGBF& theB) +{ + return Image_ColorSub3 (theA, theB); +} + +inline Image_ColorBGRF operator- (const Image_ColorBGRF& theA, const Image_ColorBGRF& theB) +{ + return Image_ColorSub3 (theA, theB); +} + +template +inline ColorType_t Image_ColorSub4 (const ColorType_t& theA, const ColorType_t& theB) +{ + ColorType_t aRes = { theA.v[0] - theB.v[0], + theA.v[1] - theB.v[1], + theA.v[2] - theB.v[2], + theA.v[3] - theB.v[3] }; + return aRes; +} + +inline Image_ColorRGBA operator- (const Image_ColorRGBA& theA, const Image_ColorRGBA& theB) +{ + return Image_ColorSub4 (theA, theB); +} + +inline Image_ColorBGRA operator- (const Image_ColorBGRA& theA, const Image_ColorBGRA& theB) +{ + return Image_ColorSub4 (theA, theB); +} + +inline Image_ColorRGB32 operator- (const Image_ColorRGB32& theA, const Image_ColorRGB32& theB) +{ + return Image_ColorSub4 (theA, theB); +} + +inline Image_ColorBGR32 operator- (const Image_ColorBGR32& theA, const Image_ColorBGR32& theB) +{ + return Image_ColorSub4 (theA, theB); +} + +inline Image_ColorRGBAF operator- (const Image_ColorRGBAF& theA, const Image_ColorRGBAF& theB) +{ + return Image_ColorSub4 (theA, theB); +} + +inline Image_ColorBGRAF operator- (const Image_ColorBGRAF& theA, const Image_ColorBGRAF& theB) +{ + return Image_ColorSub4 (theA, theB); +} + +#endif // _Image_Color_H__ diff --git a/src/Image/Image_Diff.cxx b/src/Image/Image_Diff.cxx new file mode 100644 index 0000000000..5b28f18124 --- /dev/null +++ b/src/Image/Image_Diff.cxx @@ -0,0 +1,526 @@ +// Created on: 2012-07-10 +// Created by: VRO +// Copyright (c) 2012 OPEN CASCADE SAS +// +// The content of this file is subject to the Open CASCADE Technology Public +// License Version 6.5 (the "License"). You may not use the content of this file +// except in compliance with the License. Please obtain a copy of the License +// at http://www.opencascade.org and read it completely before using this file. +// +// The Initial Developer of the Original Code is Open CASCADE S.A.S., having its +// main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France. +// +// The Original Code and all software distributed under the License is +// distributed on an "AS IS" basis, without warranty of any kind, and the +// Initial Developer hereby disclaims all such warranties, including without +// limitation, any warranties of merchantability, fitness for a particular +// purpose or non-infringement. Please see the License for the specific terms +// and conditions governing the rights and limitations under the License. + +#include +#include + +#include + +#include + +IMPLEMENT_STANDARD_HANDLE (Image_Diff, Standard_Transient) +IMPLEMENT_STANDARD_RTTIEXT(Image_Diff, Standard_Transient) + +//! Dot squared for difference of two colors +inline Standard_Integer dotSquared (const Image_ColorRGB& theColor) +{ + // explicitly convert to integer + const Standard_Integer r = theColor.r(); + const Standard_Integer g = theColor.g(); + const Standard_Integer b = theColor.b(); + return r * r + g * g + b * b; +} + +//! @return true if pixel is black +inline bool isBlack (const Image_ColorRGB& theColor) +{ + return theColor.r() == 0 + && theColor.g() == 0 + && theColor.b() == 0; +} + +//! Converts a pixel position (row, column) to one integer value +inline Standard_Size pixel2Int (const Standard_Size aRow, + const Standard_Size aCol) +{ + return aCol + (aRow << 15); +} + +//! Converts an integer value to pixel coordinates (row, column) +inline void int2Pixel (const Standard_Size theValue, + Standard_Size& theRow, + Standard_Size& theCol) +{ + theRow = (theValue >> 15); + theCol = theValue - (theRow << 15); +} + +namespace +{ + static const Standard_Size NEIGHBOR_PIXELS_NB = 8; + struct + { + Standard_Integer row_inc; + Standard_Integer col_inc; + + inline Standard_Size pixel2Int (const Standard_Size theRowCenter, + const Standard_Size theColCenter) const + { + return ::pixel2Int (theRowCenter + Standard_Size(row_inc), + theColCenter + Standard_Size(col_inc)); + } + + inline bool isBlack (const Image_PixMapData& theData, + const Standard_Size theRowCenter, + const Standard_Size theColCenter) const + { + return ::isBlack (theData.Value (theRowCenter + Standard_Size(row_inc), + theColCenter + Standard_Size(col_inc))); + } + } + static const NEIGHBOR_PIXELS[NEIGHBOR_PIXELS_NB] = + { + {-1, -1}, {-1, 0}, {-1, 1}, + { 0, -1}, { 0, 1}, + { 1, -1}, { 1, 0}, { 1, 1} + }; + + static bool isSupportedFormat (const Image_PixMap::ImgFormat theFormat) + { + return theFormat == Image_PixMap::ImgRGB + || theFormat == Image_PixMap::ImgBGR + || theFormat == Image_PixMap::ImgRGB32 + || theFormat == Image_PixMap::ImgBGR32 + || theFormat == Image_PixMap::ImgRGBA + || theFormat == Image_PixMap::ImgBGRA; + } +}; + +// ======================================================================= +// function : Image_Diff +// purpose : +// ======================================================================= +Image_Diff::Image_Diff() +: myColorTolerance (0.0), + myIsBorderFilterOn (Standard_False) +{ + // +} + +// ======================================================================= +// function : ~Image_Diff +// purpose : +// ======================================================================= +Image_Diff::~Image_Diff() +{ + releaseGroupsOfDiffPixels(); +} + +// ======================================================================= +// function : Init +// purpose : +// ======================================================================= +Standard_Boolean Image_Diff::Init (const Handle(Image_PixMap)& theImageRef, + const Handle(Image_PixMap)& theImageNew, + const Standard_Boolean theToBlackWhite) +{ + myImageRef.Nullify(); + myImageNew.Nullify(); + myDiffPixels.Clear(); + releaseGroupsOfDiffPixels(); + if (theImageRef.IsNull() || theImageNew.IsNull() + || theImageRef->IsEmpty() || theImageNew->IsEmpty() + || theImageRef->SizeX() != theImageNew->SizeX() + || theImageRef->SizeY() != theImageNew->SizeY() + || theImageRef->Format() != theImageNew->Format()) + { + std::cerr << "Images has different format or dimensions\n"; + return Standard_False; + } + else if (!isSupportedFormat (theImageRef->Format())) + { + std::cerr << "Images has unsupported pixel format\n"; + return Standard_False; + } + else if (theImageRef->SizeX() >= 0xFFFF + || theImageRef->SizeY() >= 0xFFFF) + { + std::cerr << "Image too large\n"; + return Standard_False; + } + + myImageRef = theImageRef; + myImageNew = theImageNew; + + if (theToBlackWhite) + { + // Convert the images to white/black + const Image_ColorRGB aWhite = {{255, 255, 255}}; + Image_PixMapData& aDataRef = myImageRef->EditData(); + Image_PixMapData& aDataNew = myImageNew->EditData(); + for (Standard_Size aRow = 0; aRow < aDataRef.SizeY(); ++aRow) + { + for (Standard_Size aCol = 0; aCol < aDataRef.SizeY(); ++aCol) + { + Image_ColorRGB& aPixel1 = aDataRef.ChangeValue (aRow, aCol); + Image_ColorRGB& aPixel2 = aDataNew.ChangeValue (aRow, aCol); + if (!isBlack (aPixel1)) + { + aPixel1 = aWhite; + } + if (!isBlack (aPixel2)) + { + aPixel2 = aWhite; + } + } + } + } + + return Standard_True; +} + + +// ======================================================================= +// function : Init +// purpose : +// ======================================================================= +Standard_Boolean Image_Diff::Init (const TCollection_AsciiString& theImgPathRef, + const TCollection_AsciiString& theImgPathNew, + const Standard_Boolean theToBlackWhite) +{ + Handle(Image_AlienPixMap) anImgRef = new Image_AlienPixMap(); + Handle(Image_AlienPixMap) anImgNew = new Image_AlienPixMap(); + if (!anImgRef->Load (theImgPathRef) + || !anImgNew->Load (theImgPathNew)) + { + std::cerr << "Failed to load image(s) file(s)\n"; + return Standard_False; + } + return Init (anImgRef, anImgNew, theToBlackWhite); +} + +// ======================================================================= +// function : SetColorTolerance +// purpose : +// ======================================================================= +void Image_Diff::SetColorTolerance (const Standard_Real theTolerance) +{ + myColorTolerance = theTolerance; +} + +// ======================================================================= +// function : ColorTolerance +// purpose : +// ======================================================================= +Standard_Real Image_Diff::ColorTolerance() const +{ + return myColorTolerance; +} + +// ======================================================================= +// function : SetBorderFilterOn +// purpose : +// ======================================================================= +void Image_Diff::SetBorderFilterOn (const Standard_Boolean theToIgnore) +{ + myIsBorderFilterOn = theToIgnore; +} + +// ======================================================================= +// function : IsBorderFilterOn +// purpose : +// ======================================================================= +Standard_Boolean Image_Diff::IsBorderFilterOn() const +{ + return myIsBorderFilterOn; +} + +// ======================================================================= +// function : Compare +// purpose : +// ======================================================================= +Standard_Integer Image_Diff::Compare() +{ + // Number of different pixels (by color) + Standard_Integer aNbDiffColors = 0; + myDiffPixels.Clear(); + + if (myImageRef.IsNull() || myImageNew.IsNull()) + { + return -1; + } + + // Tolerance of comparison operation for color + // Maximum difference between colors (white - black) = 100% + Image_ColorRGB aDiff = {{255, 255, 255}}; + const Standard_Integer aMaxDiffColor = dotSquared (aDiff); + const Standard_Integer aDiffThreshold = Standard_Integer(Standard_Real(aMaxDiffColor) * myColorTolerance); + + // we don't care about RGB/BGR/RGBA/BGRA/RGB32/BGR32 differences + // because we just compute summ of r g b components + const Image_PixMapData& aDataRef = myImageRef->ReadData(); + const Image_PixMapData& aDataNew = myImageNew->ReadData(); + + // compare colors of each pixel + for (Standard_Size aRow = 0; aRow < myImageRef->SizeY(); ++aRow) + { + for (Standard_Size aCol = 0; aCol < myImageRef->SizeX(); ++aCol) + { + aDiff = aDataNew.Value (aRow, aCol) - aDataRef.Value (aRow, aCol); + if (dotSquared (aDiff) > aDiffThreshold) + { + const Standard_Size aValue = pixel2Int (aRow, aCol); + myDiffPixels.Append (aValue); + ++aNbDiffColors; + } + } + } + + // take into account a border effect + if (myIsBorderFilterOn && myDiffPixels.Length() > 0) + { + aNbDiffColors = ignoreBorderEffect(); + } + + return aNbDiffColors; +} + +// ======================================================================= +// function : SaveDiffImage +// purpose : +// ======================================================================= +Standard_Boolean Image_Diff::SaveDiffImage (Image_PixMap& theDiffImage) const +{ + if (myImageRef.IsNull() || myImageNew.IsNull()) + { + return Standard_False; + } + + if (theDiffImage.IsEmpty() + || theDiffImage.SizeX() != myImageRef->SizeX() + || theDiffImage.SizeY() != myImageRef->SizeY() + || !isSupportedFormat (theDiffImage.Format())) + { + if (!theDiffImage.InitTrash (Image_PixMap::ImgRGB, myImageRef->SizeX(), myImageRef->SizeY())) + { + return Standard_False; + } + } + + Standard_Size aRow, aCol; + const Image_ColorRGB aWhite = {{255, 255, 255}}; + Image_PixMapData& aDataOut = theDiffImage.EditData(); + + // initialize black image for dump + memset (theDiffImage.ChangeData(), 0, theDiffImage.SizeBytes()); + if (myGroupsOfDiffPixels.IsEmpty()) + { + if (myIsBorderFilterOn) + { + return Standard_True; + } + + for (Standard_Integer aPixelId = 0; aPixelId < myDiffPixels.Length(); ++aPixelId) + { + const Standard_Size aValue = myDiffPixels.Value (aPixelId); + int2Pixel (aValue, aRow, aCol); + aDataOut.ChangeValue (aRow, aCol) = aWhite; + } + + return Standard_True; + } + + Standard_Integer aGroupId = 1; + for (ListOfMapOfInteger::Iterator aGrIter (myGroupsOfDiffPixels); aGrIter.More(); aGrIter.Next(), ++aGroupId) + { + if (myLinearGroups.Contains (aGroupId)) + { + continue; // skip linear groups + } + + const TColStd_MapOfInteger* aGroup = aGrIter.Value(); + for (TColStd_MapIteratorOfMapOfInteger aPixelIter(*aGroup); + aPixelIter.More(); aPixelIter.Next()) + { + int2Pixel (aPixelIter.Key(), aRow, aCol); + aDataOut.ChangeValue (aRow, aCol) = aWhite; + } + } + + return Standard_True; +} + +// ======================================================================= +// function : SaveDiffImage +// purpose : +// ======================================================================= +Standard_Boolean Image_Diff::SaveDiffImage (const TCollection_AsciiString& theDiffPath) const +{ + if (myImageRef.IsNull() || myImageNew.IsNull() || theDiffPath.IsEmpty()) + { + return Standard_False; + } + + Image_AlienPixMap aDiff; + if (!aDiff.InitTrash (Image_PixMap::ImgRGB, myImageRef->SizeX(), myImageRef->SizeY()) + || !SaveDiffImage (aDiff)) + { + return Standard_False; + } + + // save image + return aDiff.Save (theDiffPath); +} + +// ======================================================================= +// function : ignoreBorderEffect +// purpose : +// ======================================================================= +Standard_Integer Image_Diff::ignoreBorderEffect() +{ + if (myImageRef.IsNull() || myImageNew.IsNull()) + { + return 0; + } + + const Image_PixMapData& aDataRef = myImageRef->ReadData(); + + // allocate groups of different pixels + releaseGroupsOfDiffPixels(); + + // Find a different area (a set of close to each other pixels which colors differ in both images). + // It filters alone pixels with different color. + Standard_Size aRow1, aCol1, aRow2, aCol2; + Standard_Integer aLen1 = (myDiffPixels.Length() > 0) ? (myDiffPixels.Length() - 1) : 0; + for (Standard_Integer aPixelId1 = 0; aPixelId1 < aLen1; ++aPixelId1) + { + const Standard_Size aValue1 = myDiffPixels.Value (aPixelId1); + int2Pixel (aValue1, aRow1, aCol1); + + // Check other pixels in the list looking for a neighbour of this one + for (Standard_Integer aPixelId2 = aPixelId1 + 1; aPixelId2 < myDiffPixels.Length(); ++aPixelId2) + { + const Standard_Size aValue2 = myDiffPixels.Value (aPixelId2); + int2Pixel (aValue2, aRow2, aCol2); + if (std::abs (ptrdiff_t (aCol1 - aCol2)) <= 1 && + std::abs (ptrdiff_t (aRow1 - aRow2)) <= 1) + { + // A neighbour is found. Create a new group and add both pixels. + if (myGroupsOfDiffPixels.IsEmpty()) + { + TColStd_MapOfInteger* aGroup = new TColStd_MapOfInteger(); + aGroup->Add (aValue1); + aGroup->Add (aValue2); + myGroupsOfDiffPixels.Append (aGroup); + } + else + { + // Find a group the pixels belong to. + Standard_Boolean isFound = Standard_False; + for (ListOfMapOfInteger::Iterator aGrIter (myGroupsOfDiffPixels); aGrIter.More(); aGrIter.Next()) + { + TColStd_MapOfInteger*& aGroup = aGrIter.ChangeValue(); + if (aGroup->Contains (aValue1)) + { + aGroup->Add (aValue2); + isFound = Standard_True; + break; + } + } + + if (!isFound) + { + // Create a new group + TColStd_MapOfInteger* aGroup = new TColStd_MapOfInteger(); + aGroup->Add (aValue1); + aGroup->Add (aValue2); + myGroupsOfDiffPixels.Append (aGroup); + } + } + } + } + } + + // filter linear groups which represent border of a solid shape + Standard_Integer aGroupId = 1; + for (ListOfMapOfInteger::Iterator aGrIter (myGroupsOfDiffPixels); aGrIter.More(); aGrIter.Next(), ++aGroupId) + { + Standard_Integer aNeighboursNb = 0; + Standard_Boolean isLine = Standard_True; + const TColStd_MapOfInteger* aGroup = aGrIter.Value(); + for (TColStd_MapIteratorOfMapOfInteger aPixelIter (*aGroup); aPixelIter.More(); aPixelIter.Next()) + { + int2Pixel (aPixelIter.Key(), aRow1, aCol1); + aNeighboursNb = 0; + + // pixels of a line have only 1 or 2 neighbour pixels inside the same group + // check all neighbour pixels on presence in the group + for (Standard_Size aNgbrIter = 0; aNgbrIter < NEIGHBOR_PIXELS_NB; ++aNgbrIter) + { + if (aGroup->Contains (NEIGHBOR_PIXELS[aNgbrIter].pixel2Int (aRow1, aCol1))) + { + ++aNeighboursNb; + } + } + + if (aNeighboursNb > 2) + { + isLine = Standard_False; + break; + } + } // for pixels inside group... + + if (isLine) + { + // Test a pixel of the linear group on belonging to a solid shape. + // Consider neighbour pixels of the last pixel of the linear group in the 1st image. + // If the pixel has greater than 1 not black neighbour pixel, it is a border of a shape. + // Otherwise, it may be a topological edge, for example. + aNeighboursNb = 0; + for (Standard_Size aNgbrIter = 0; aNgbrIter < NEIGHBOR_PIXELS_NB; ++aNgbrIter) + { + if (!NEIGHBOR_PIXELS[aNgbrIter].isBlack (aDataRef, aRow1, aCol1)) + { + ++aNeighboursNb; + } + } + + if (aNeighboursNb > 1) + { + myLinearGroups.Add (aGroupId); + } + } + } // for groups... + + // number of different groups of pixels (except linear groups) + Standard_Integer aNbDiffColors = 0; + aGroupId = 1; + for (ListOfMapOfInteger::Iterator aGrIter (myGroupsOfDiffPixels); aGrIter.More(); aGrIter.Next(), ++aGroupId) + { + if (!myLinearGroups.Contains (aGroupId)) + ++aNbDiffColors; + } + + return aNbDiffColors; +} + +// ======================================================================= +// function : releaseGroupsOfDiffPixels +// purpose : +// ======================================================================= +void Image_Diff::releaseGroupsOfDiffPixels() +{ + for (ListOfMapOfInteger::Iterator aGrIter (myGroupsOfDiffPixels); aGrIter.More(); aGrIter.Next()) + { + TColStd_MapOfInteger*& aGroup = aGrIter.ChangeValue(); + delete aGroup; + } + myGroupsOfDiffPixels.Clear(); + myLinearGroups.Clear(); +} diff --git a/src/Image/Image_Diff.hxx b/src/Image/Image_Diff.hxx new file mode 100644 index 0000000000..1f1541c6be --- /dev/null +++ b/src/Image/Image_Diff.hxx @@ -0,0 +1,135 @@ +// Created on: 2012-07-10 +// Created by: VRO +// Copyright (c) 2012 OPEN CASCADE SAS +// +// The content of this file is subject to the Open CASCADE Technology Public +// License Version 6.5 (the "License"). You may not use the content of this file +// except in compliance with the License. Please obtain a copy of the License +// at http://www.opencascade.org and read it completely before using this file. +// +// The Initial Developer of the Original Code is Open CASCADE S.A.S., having its +// main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France. +// +// The Original Code and all software distributed under the License is +// distributed on an "AS IS" basis, without warranty of any kind, and the +// Initial Developer hereby disclaims all such warranties, including without +// limitation, any warranties of merchantability, fitness for a particular +// purpose or non-infringement. Please see the License for the specific terms +// and conditions governing the rights and limitations under the License. + +#ifndef _Image_Diff_H__ +#define _Image_Diff_H__ + +#include +#include +#include +#include +#include + +//! This class compares two images pixel-by-pixel. +//! It uses the following methods to ignore the difference between images: +//! - Black/White comparison. It makes the images 2-colored before the comparison. +//! - Equality with tolerance. Colors of two pixels are considered the same if the +//! differnce of their color is less than a tolerance. +//! - Border filter. The algorithm ignores alone independent pixels, +//! which are different on both images, ignores the "border effect" - +//! the difference caused by triangles located at angle about 0 or 90 degrees to the user. +//! +//! Border filter ignores a difference in implementation of +//! anti-aliasing and other effects on boundary of a shape. +//! The triangles of a boundary zone are usually located so that their normals point aside the user +//! (about 90 degree between the normal and the direction to the user's eye). +//! Deflection of the light for such a triangle depends on implementation of the video driver. +//! In order to skip this difference the following algorithm is used: +//! a) "Different" pixels are groupped and checked on "one-pixel width line". +//! indeed, the pixels may represent not a line, but any curve. +//! But the width of this curve should be not more than a pixel. +//! This group of pixels become a candidate to be ignored because of boundary effect. +//! b) The group of pixels is checked on belonging to a "shape". +//! Neighbour pixels are checked from the reference image. +//! This test confirms a fact that the group of pixels belongs to a shape and +//! represent a boundary of the shape. +//! In this case the whole group of pixels is ignored (considered as same). +//! Otherwise, the group of pixels may represent a geometrical curve in the viewer 3D +//! and should be considered as "different". +class Image_Diff : public Standard_Transient +{ + +public: + + //! An empty constructor. Init() should be called for initialization. + Standard_EXPORT Image_Diff(); + + //! Desctructor. + Standard_EXPORT virtual ~Image_Diff(); + + //! Initialize algorithm by two images. + //! @return false if images has different or unsupported pixel format. + Standard_EXPORT Standard_Boolean Init (const Handle(Image_PixMap)& theImageRef, + const Handle(Image_PixMap)& theImageNew, + const Standard_Boolean theToBlackWhite = Standard_False); + + //! Initialize algorithm by two images (will be loaded from files). + //! @return false if images couldn't be opened or their format is unsupported. + Standard_EXPORT Standard_Boolean Init (const TCollection_AsciiString& theImgPathRef, + const TCollection_AsciiString& theImgPathNew, + const Standard_Boolean theToBlackWhite = Standard_False); + + //! Color tolerance for equality check. Should be within range 0..1: + //! Corresponds to a difference between white and black colors (maximum difference). + //! By default, the tolerance is equal to 0 thus equality check will return false for any different colors. + Standard_EXPORT void SetColorTolerance (const Standard_Real theTolerance); + + //! Color tolerance for equality check. + Standard_EXPORT Standard_Real ColorTolerance() const; + + //! Sets taking into account (ignoring) a "border effect" on comparison of images. + //! The border effect is caused by a border of shaded shapes in the viewer 3d. + //! Triangles of this area are located at about 0 or 90 degrees to the user. + //! Therefore, they deflect light differently according to implementation of a video card driver. + //! This flag allows to detect such a "border" area and skip it from comparison of images. + //! Filter turned OFF by default. + Standard_EXPORT void SetBorderFilterOn (const Standard_Boolean theToIgnore); + + //! Returns a flag of taking into account (ignoring) a border effect in comparison of images. + Standard_EXPORT Standard_Boolean IsBorderFilterOn() const; + + //! Compares two images. It returns a number of different pixels (or groups of pixels). + //! It returns -1 if algorithm not initialized before. + Standard_EXPORT Standard_Integer Compare(); + + //! Saves a difference between two images as white pixels on black backgroud. + Standard_EXPORT Standard_Boolean SaveDiffImage (Image_PixMap& theDiffImage) const; + + //! Saves a difference between two images as white pixels on black backgroud. + Standard_EXPORT Standard_Boolean SaveDiffImage (const TCollection_AsciiString& theDiffPath) const; + +protected: + + //! Perform border filter algorithm. + Standard_EXPORT Standard_Integer ignoreBorderEffect(); + + //! Release dynamically allocated memory. + Standard_EXPORT void releaseGroupsOfDiffPixels(); + +protected: + + typedef NCollection_List ListOfMapOfInteger; + + Handle(Image_PixMap) myImageRef; //!< reference image to compare (from) + Handle(Image_PixMap) myImageNew; //!< new image to compare (to) + Standard_Real myColorTolerance; //!< tolerance for equality check (0..1, 0 - any not equal, 1 - opposite colors) + Standard_Boolean myIsBorderFilterOn; //!< perform algorithm with border effect filter + ListOfMapOfInteger myGroupsOfDiffPixels; + NCollection_Vector myDiffPixels; //!< different pixels (position packed into integer) + TColStd_MapOfInteger myLinearGroups; + +public: + + DEFINE_STANDARD_RTTI(Image_Diff) // Type definition + +}; + +DEFINE_STANDARD_HANDLE(Image_Diff, Standard_Transient) + +#endif // _Image_Diff_H__ diff --git a/src/Image/Image_PixMap.cdl b/src/Image/Image_PixMap.cdl deleted file mode 100644 index ad528f3721..0000000000 --- a/src/Image/Image_PixMap.cdl +++ /dev/null @@ -1,147 +0,0 @@ --- Created on: 2010-09-16 --- Created by: KGV --- Copyright (c) 2010-2012 OPEN CASCADE SAS --- --- The content of this file is subject to the Open CASCADE Technology Public --- License Version 6.5 (the "License"). You may not use the content of this file --- except in compliance with the License. Please obtain a copy of the License --- at http://www.opencascade.org and read it completely before using this file. --- --- The Initial Developer of the Original Code is Open CASCADE S.A.S., having its --- main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France. --- --- The Original Code and all software distributed under the License is --- distributed on an "AS IS" basis, without warranty of any kind, and the --- Initial Developer hereby disclaims all such warranties, including without --- limitation, any warranties of merchantability, fitness for a particular --- purpose or non-infringement. Please see the License for the specific terms --- and conditions governing the rights and limitations under the License. - - -class PixMap from Image - - ---Version: - - ---Purpose: This class defines a system-independent bitmap - - ---Keywords: Bitmap, Pixmap - -inherits - PixMap from Aspect - -uses - Handle from Aspect, - TypeOfImage from Image, - HPrivateImage from Image, - CRawBufferData from Image, - Color from Quantity, - Parameter from Quantity - -raises - PixmapDefinitionError from Aspect, - PixmapError from Aspect - -is - - Create ( theWidth, theHeight : Integer from Standard; - theType : TypeOfImage from Image ) - returns mutable PixMap from Image - raises PixmapDefinitionError from Aspect; - ---Level: Public - ---Purpose: - -- Allocate the bitmap with requested dimensions. - -- Allowed image types: - -- - Image_TOI_RGB (color image, 1 byte per component); - -- - Image_TOI_RGBA (color image with alpha channel); - -- - Image_TOI_RGBF (color image, 1 float per component); - -- - Image_TOI_RGBAF (color image with alpha channel); - -- - Image_TOI_FLOAT (grey image, 1 float per pixel). - - Create ( theDataPtr : PByte from Standard; - theWidth, theHeight : Integer from Standard; - thePitch : Integer from Standard; - theBitsPerPixel : Integer from Standard; - theIsTopDown : Boolean from Standard ) - returns mutable PixMap from Image - raises PixmapDefinitionError from Aspect; - ---Level: Public - ---Purpose: - -- Create a bitmap by copying an existing buffer. - - --------------------------------------------------- - -- Category: Methods to modify the class definition - --------------------------------------------------- - - Destroy ( me : mutable ) - ---Level: Advanced - ---Purpose: - -- Destroies the Bitmap - ---C++: alias ~ - ---Trigger: Raises if Bitmap is not defined properly - raises PixmapError from Aspect is virtual; - - Dump ( me; - theFilename : CString from Standard; - theGammaCorr : Real from Standard = 1.0 ) - returns Boolean from Standard - ---Level: Advanced - ---Purpose: - -- Dumps the Bitmap to an image file with - -- an optional gamma correction value - -- and returns TRUE if the dump occurs normaly. - raises PixmapError from Aspect is virtual; - - ---------------------------- - -- Category: Inquire methods - ---------------------------- - - PixmapID ( me ) returns Handle from Aspect is virtual; - ---Level: Advanced - ---Purpose: - -- Returns NULL handle - ---Category: Inquire methods - - ---------------------------- - -- Category: Access methods - ---------------------------- - - AccessBuffer ( me : in; - theBufferInfo : in out CRawBufferData from Image ) - is static; - ---Purpose: - -- Fill the structure for low-level access to the bitmap data. - -- It is up to you to interpret these bytes correctly! - -- Important notice: image stored upside-down in the memory, - -- first image row is an last scanline in - -- the memory buffer. - -- If image was created with type Image_TOI_FLOAT buffer - -- format will be set to TDepthComponent. You can override - -- this field with another one-channel buffer format because - -- it useless for bitmap definition. - - PixelColor ( me : in; - theX, theY : in Integer from Standard ) - returns Color from Quantity - is virtual; - ---Purpose: - -- Returns the pixel color. This function is relatively slow, - -- use AccessBuffer() instead for stream operations. - -- Note that this function convert input theY coordinate - -- to count off from top of an image (while in memory it stored - -- upside-down). - - PixelColor ( me : in; - theX, theY : in Integer from Standard; - theAlpha : out Parameter from Quantity ) - returns Color from Quantity; - ---Purpose: - -- Returns the pixel color. This function is relatively slow, - -- use AccessBuffer() instead for stream operations. - -- theAlpha argument is set to color intensity (0 - transparent, 1 - opaque) - -- Note that this function convert input theY coordinate - -- to count off from top of an image (while in memory it stored - -- upside-down). - -fields - myImage : HPrivateImage from Image is protected; -end PixMap; diff --git a/src/Image/Image_PixMap.cxx b/src/Image/Image_PixMap.cxx index 3065861294..14b3f2ac6d 100644 --- a/src/Image/Image_PixMap.cxx +++ b/src/Image/Image_PixMap.cxx @@ -1,6 +1,6 @@ -// Created on: 2010-09-16 -// Created by: KGV -// Copyright (c) 2010-2012 OPEN CASCADE SAS +// Created on: 2012-07-18 +// Created by: Kirill GAVRILOV +// Copyright (c) 2012 OPEN CASCADE SAS // // The content of this file is subject to the Open CASCADE Technology Public // License Version 6.5 (the "License"). You may not use the content of this file @@ -17,414 +17,209 @@ // purpose or non-infringement. Please see the License for the specific terms // and conditions governing the rights and limitations under the License. -#ifdef HAVE_CONFIG_H -# include +#include + +#ifndef _MSC_VER + #include #endif -#ifdef HAVE_FREEIMAGE - #include - #include - /* OCC22216 NOTE: linker dependency can be switched off by undefining macro */ - #ifdef _MSC_VER - #pragma comment( lib, "FreeImage.lib" ) - #pragma comment( lib, "FreeImagePlus.lib" ) - #endif +template +inline TypePtr MemAllocAligned (const Standard_Size& theBytesCount, + const Standard_Size& theAlign = 16) +{ +#if defined(_MSC_VER) + return (TypePtr )_aligned_malloc (theBytesCount, theAlign); #else - #include - #include - - #if (defined(BYTE_ORDER) && BYTE_ORDER==BIG_ENDIAN) || \ - (defined(__BYTE_ORDER) && __BYTE_ORDER==__BIG_ENDIAN) || \ - defined(__BIG_ENDIAN__) - #define THE_BIGENDIAN - #endif - - // dummy class which can only dump to PPM format - class fipImage - { - public: - - typedef struct tagRGBQuad { - #ifndef THE_BIGENDIAN - Standard_Byte rgbBlue; - Standard_Byte rgbGreen; - Standard_Byte rgbRed; - #else - Standard_Byte rgbRed; - Standard_Byte rgbGreen; - Standard_Byte rgbBlue; - #endif - Standard_Byte rgbReserved; - } RGBQuad_t; - - public: - - fipImage() - : myDataPtr(NULL), - mySizeX(0), - mySizeY(0), - myBytesPerLine(0), - myBytesPerPixel(3) - { - // - } - - fipImage (const Standard_Integer theSizeX, const Standard_Integer theSizeY, - const Standard_Integer theBytesPerLine = 0, const Standard_Integer theBytesPerPixel = 3) - : myDataPtr(NULL), - mySizeX (theSizeX), - mySizeY (theSizeY), - myBytesPerLine (theBytesPerLine), - myBytesPerPixel (theBytesPerPixel) - { - if (myBytesPerLine == 0) - { - myBytesPerLine = mySizeX * myBytesPerPixel; - } - myDataPtr = new Standard_Byte[myBytesPerLine * mySizeY]; - } - - ~fipImage() - { - delete[] myDataPtr; - } - - Standard_Integer getHeight() const - { - return mySizeY; - } - - Standard_Integer getWidth() const - { - return mySizeX; - } - - Standard_Integer getBytesPerPixel() const - { - return myBytesPerPixel; - } - - Standard_Integer getBytesPerLine() const - { - return myBytesPerLine; - } - - Standard_Byte* getData() const - { - return myDataPtr; - } - - Standard_Byte* getScanLine (const Standard_Integer theRow) const - { - return &myDataPtr[theRow * myBytesPerLine]; - } - - Quantity_Color getPixelColor (const Standard_Integer theCol, - const Standard_Integer theRow, - Quantity_Parameter& theAlpha) const - { - RGBQuad_t* aPixel = (RGBQuad_t* )&getScanLine (theRow)[theCol * myBytesPerPixel]; - theAlpha = (myBytesPerPixel > 3) ? (Standard_Real (aPixel->rgbReserved) / 255.0) : 1.0; - return Quantity_Color (Standard_Real (aPixel->rgbRed) / 255.0, - Standard_Real (aPixel->rgbGreen) / 255.0, - Standard_Real (aPixel->rgbBlue) / 255.0, - Quantity_TOC_RGB); - } - - Standard_Boolean savePPM (const Standard_CString theFileName) const - { - // Open file - FILE* pFile = fopen (theFileName, "wb"); - if (pFile == NULL) - { - return Standard_False; - } - - // Write header - fprintf (pFile, "P6\n%d %d\n255\n", mySizeX, mySizeY); - - // Write pixel data - Standard_Byte* aScanLine; - RGBQuad_t* aPixel; - // image stored upside-down - for (Standard_Integer aRow = mySizeY - 1; aRow >= 0; --aRow) - { - aScanLine = getScanLine (aRow); - for (Standard_Integer aCol = 0; aCol < mySizeX; ++aCol) - { - aPixel = (RGBQuad_t* )&aScanLine[aCol * myBytesPerPixel]; - fwrite (&aPixel->rgbRed, 1, 1, pFile); - fwrite (&aPixel->rgbGreen, 1, 1, pFile); - fwrite (&aPixel->rgbBlue, 1, 1, pFile); - } - } - - // Close file - fclose (pFile); - return Standard_True; - } - - Standard_Integer getMaxRowAligmentBytes() const - { - Standard_Integer aDeltaBytes = myBytesPerLine - myBytesPerPixel * mySizeX; - for (Standard_Integer anAligment = 16; anAligment > 1; anAligment /= 2) - { - if (isRowAlignedTo (anAligment, aDeltaBytes)) - { - return anAligment; - } - } - return 1; - } - - private: - - Standard_Boolean isRowAlignedTo (const Standard_Integer theAligmentBytes, - const Standard_Integer theDeltaBytes) const - { - return (theDeltaBytes < theAligmentBytes) && - ((myBytesPerLine % theAligmentBytes) == 0); - } + return (TypePtr ) _mm_malloc (theBytesCount, theAlign); +#endif +} - private: +inline void MemFreeAligned (void* thePtrAligned) +{ +#if defined(_MSC_VER) + _aligned_free (thePtrAligned); +#else + _mm_free (thePtrAligned); +#endif +} - Standard_Byte* myDataPtr; - Standard_Integer mySizeX; - Standard_Integer mySizeY; - Standard_Integer myBytesPerLine; - Standard_Integer myBytesPerPixel; +IMPLEMENT_STANDARD_HANDLE (Image_PixMap, Standard_Transient) +IMPLEMENT_STANDARD_RTTIEXT(Image_PixMap, Standard_Transient) - }; -#endif +// ======================================================================= +// function : Image_PixMap +// purpose : +// ======================================================================= +Image_PixMap::Image_PixMap() +: myImgFormat (Image_PixMap::ImgGray), + myIsOwnPointer (true) +{ + memset (&myData, 0, sizeof(myData)); + myData.mySizeBPP = 1; + myData.myTopToDown = 1; + setFormat (Image_PixMap::ImgGray); +} -#include -#include +// ======================================================================= +// function : ~Image_PixMap +// purpose : +// ======================================================================= +Image_PixMap::~Image_PixMap() +{ + Clear(); +} -//======================================================================= -//function : Image_PixMap -//purpose : -//======================================================================= -Image_PixMap::Image_PixMap (const Standard_Integer theWidth, - const Standard_Integer theHeight, - const Image_TypeOfImage theType) -: Aspect_PixMap (theWidth, theHeight, 1), - myImage() +Standard_Size Image_PixMap::SizePixelBytes (const Image_PixMap::ImgFormat thePixelFormat) { -#ifdef HAVE_FREEIMAGE - FREE_IMAGE_TYPE aFIType = FIT_UNKNOWN; - int aBitsPerPixel = 0; - switch (theType) + switch (thePixelFormat) { - case Image_TOI_RGBA: - aFIType = FIT_BITMAP; - aBitsPerPixel = 32; - break; - case Image_TOI_RGBF: - aFIType = FIT_RGBF; - aBitsPerPixel = 96; - break; - case Image_TOI_RGBAF: - aFIType = FIT_RGBAF; - aBitsPerPixel = 128; - break; - case Image_TOI_FLOAT: - aFIType = FIT_FLOAT; - aBitsPerPixel = 32; - break; - case Image_TOI_RGB: + case ImgGrayF: + return sizeof(float); + case ImgRGBAF: + case ImgBGRAF: + return sizeof(float) * 4; + case ImgRGBF: + case ImgBGRF: + return sizeof(float) * 3; + case ImgRGBA: + case ImgBGRA: + return 4; + case ImgRGB32: + case ImgBGR32: + return 4; + case ImgRGB: + case ImgBGR: + return 3; + case ImgGray: default: - aFIType = FIT_BITMAP; - aBitsPerPixel = 24; - break; - } - myImage = new fipImage (aFIType, theWidth, theHeight, aBitsPerPixel); -#else - Standard_Integer aBytesPerPixel = 0; - switch (theType) - { - case Image_TOI_RGBAF: - std::cerr << "Float formats not supported\n"; - case Image_TOI_RGBA: - aBytesPerPixel = 4; - break; - case Image_TOI_RGBF: - case Image_TOI_FLOAT: - std::cerr << "Float formats not supported\n"; - case Image_TOI_RGB: - default: - aBytesPerPixel = 3; - break; + return 1; } - myImage = new fipImage (theWidth, theHeight, 0, aBytesPerPixel); - // -#endif } -//======================================================================= -//function : Image_PixMap -//purpose : -//======================================================================= -Image_PixMap::Image_PixMap (const Standard_PByte theDataPtr, - const Standard_Integer theWidth, const Standard_Integer theHeight, - const Standard_Integer thePitch, const Standard_Integer theBitsPerPixel, - const Standard_Boolean theIsTopDown) -: Aspect_PixMap (theWidth, theHeight, 1), - myImage (new fipImage()) +// ======================================================================= +// function : setFormat +// purpose : +// ======================================================================= +void Image_PixMap::setFormat (Image_PixMap::ImgFormat thePixelFormat) { -#ifdef HAVE_FREEIMAGE - *myImage = FreeImage_ConvertFromRawBits (theDataPtr, - theWidth, theHeight, - thePitch, theBitsPerPixel, - 0, 0, 0, - theIsTopDown); - if (theBitsPerPixel != 24) - { - myImage->convertTo24Bits(); - } -#else - myImage = new fipImage (theWidth, theHeight, thePitch, theBitsPerPixel / 8); - Standard_Integer aRowStart = !theIsTopDown ? 0 : (theHeight - 1); - Standard_Integer aRowDelta = !theIsTopDown ? 1 : -1; - for (Standard_Integer aRowFrom (aRowStart), aRowTo (0); - aRowFrom >= 0 && aRowFrom < theHeight; - aRowFrom += aRowDelta, ++aRowTo) - { - memcpy (myImage->getScanLine (aRowTo), - &theDataPtr[aRowFrom * thePitch], - myImage->getBytesPerLine()); - } -#endif + myImgFormat = thePixelFormat; + myData.mySizeBPP = SizePixelBytes (myImgFormat); } -//======================================================================= -//function : Destroy -//purpose : -//======================================================================= -void Image_PixMap::Destroy() +// ======================================================================= +// function : setTopDown +// purpose : +// ======================================================================= +void Image_PixMap::setTopDown() { - myImage = Image_HPrivateImage(); + myData.myTopRowPtr = ((myData.myTopToDown == 1 || myData.myDataPtr == NULL) + ? myData.myDataPtr : (myData.myDataPtr + myData.mySizeRowBytes * (myData.mySizeY - 1))); } -//======================================================================= -//function : Dump -//purpose : -//======================================================================= -Standard_Boolean Image_PixMap::Dump (const Standard_CString theFilename, - const Standard_Real theGammaCorr) const +// ======================================================================= +// function : InitWrapper +// purpose : +// ======================================================================= +bool Image_PixMap::InitWrapper (Image_PixMap::ImgFormat thePixelFormat, + Standard_Byte* theDataPtr, + const Standard_Size theSizeX, + const Standard_Size theSizeY, + const Standard_Size theSizeRowBytes) { -#ifdef HAVE_FREEIMAGE - FREE_IMAGE_FORMAT anImageFormat = FreeImage_GetFIFFromFilename (theFilename); - if (anImageFormat == FIF_UNKNOWN) + Clear (thePixelFormat); + if ((theSizeX == 0) || (theSizeY == 0) || (theDataPtr == NULL)) { - std::cerr << "Image_PixMap, image format doesn't supported!\n"; - return Standard_False; + return false; } + myData.mySizeX = theSizeX; + myData.mySizeY = theSizeY; + myData.mySizeRowBytes = (theSizeRowBytes != 0) ? theSizeRowBytes : (theSizeX * myData.mySizeBPP); + myData.myDataPtr = theDataPtr; + myIsOwnPointer = false; + setTopDown(); + return true; +} - Standard_Boolean isCopied = Standard_False; - Image_HPrivateImage anImageToDump = myImage; - if (Abs (theGammaCorr - 1.0) > gp::Resolution()) +// ======================================================================= +// function : InitTrash +// purpose : +// ======================================================================= +bool Image_PixMap::InitTrash (Image_PixMap::ImgFormat thePixelFormat, + const Standard_Size theSizeX, + const Standard_Size theSizeY, + const Standard_Size theSizeRowBytes) +{ + Clear (thePixelFormat); + if ((theSizeX == 0) || (theSizeY == 0)) { - if (!isCopied) - { - isCopied = Standard_True; - anImageToDump = new fipImage (*myImage); - } - anImageToDump->adjustGamma (theGammaCorr); + return false; } - - switch (anImageFormat) + myData.mySizeX = theSizeX; + myData.mySizeY = theSizeY; + myData.mySizeRowBytes = myData.mySizeX * myData.mySizeBPP; + if (theSizeRowBytes > myData.mySizeRowBytes) { - case FIF_GIF: - if (!isCopied) - { - isCopied = Standard_True; - anImageToDump = new fipImage (*myImage); - } - // need convertion to image with pallete - anImageToDump->colorQuantize (FIQ_NNQUANT); - break; - case FIF_EXR: - if (myImage->getImageType() == FIT_BITMAP) - { - if (!isCopied) - { - isCopied = Standard_True; - anImageToDump = new fipImage (*myImage); - } - anImageToDump->convertToType (FIT_RGBF); - } - break; - default: - if (myImage->getImageType() != FIT_BITMAP) - { - if (!isCopied) - { - isCopied = Standard_True; - anImageToDump = new fipImage (*myImage); - } - anImageToDump->convertToType (FIT_BITMAP); - } - break; + // use argument only if it greater + myData.mySizeRowBytes = theSizeRowBytes; } - return anImageToDump->save (theFilename); -#else - return myImage->savePPM (theFilename); -#endif + myData.myDataPtr = MemAllocAligned (SizeBytes()); + myIsOwnPointer = true; + setTopDown(); + return myData.myDataPtr != NULL; } -Aspect_Handle Image_PixMap::PixmapID() const +// ======================================================================= +// function : InitZero +// purpose : +// ======================================================================= +bool Image_PixMap::InitZero (Image_PixMap::ImgFormat thePixelFormat, + const Standard_Size theSizeX, + const Standard_Size theSizeY, + const Standard_Size theSizeRowBytes, + const Standard_Byte theValue) { - return Aspect_Handle(); + if (!InitTrash (thePixelFormat, theSizeX, theSizeY, theSizeRowBytes)) + { + return false; + } + memset (myData.myDataPtr, (int )theValue, SizeBytes()); + return true; } -void Image_PixMap::AccessBuffer (Image_CRawBufferData& theBuffer) const +// ======================================================================= +// function : InitCopy +// purpose : +// ======================================================================= +bool Image_PixMap::InitCopy (const Image_PixMap& theCopy) { - theBuffer.widthPx = myImage->getWidth(); - theBuffer.heightPx = myImage->getHeight(); -#ifdef HAVE_FREEIMAGE - theBuffer.rowAligmentBytes = 4; // 32 bits according to FreeImage documentation - switch (myImage->getImageType()) + if (&theCopy == this) { - case FIT_FLOAT: - theBuffer.format = TDepthComponent; - theBuffer.type = TFloat; - break; - case FIT_RGBF: - theBuffer.format = TRGB; - theBuffer.type = TFloat; - break; - case FIT_RGBAF: - theBuffer.format = TRGBA; - theBuffer.type = TFloat; - break; - case FIT_BITMAP: - default: - #if defined(FREEIMAGE_BIGENDIAN) - theBuffer.format = (myImage->getColorType() == FIC_RGBALPHA) ? TRGBA : TRGB; - #else - theBuffer.format = (myImage->getColorType() == FIC_RGBALPHA) ? TBGRA : TBGR; - #endif - theBuffer.type = TUByte; - break; + // self-copying disallowed + return false; } - theBuffer.dataPtr = myImage->accessPixels(); -#else - theBuffer.rowAligmentBytes = myImage->getMaxRowAligmentBytes(); - theBuffer.format = (myImage->getBytesPerPixel() == 4) ? TBGRA : TBGR; - theBuffer.type = TUByte; - theBuffer.dataPtr = myImage->getData(); -#endif + if (InitTrash (theCopy.myImgFormat, theCopy.myData.mySizeX, theCopy.myData.mySizeY, theCopy.myData.mySizeRowBytes)) + { + memcpy (myData.myDataPtr, theCopy.myData.myDataPtr, theCopy.SizeBytes()); + return true; + } + return false; } // ======================================================================= -// function : PixelColor +// function : Clear // purpose : // ======================================================================= -Quantity_Color Image_PixMap::PixelColor (const Standard_Integer theX, - const Standard_Integer theY) const +void Image_PixMap::Clear (Image_PixMap::ImgFormat thePixelFormat) { - Quantity_Parameter aDummy; - return PixelColor (theX, theY, aDummy); + if (myIsOwnPointer && (myData.myDataPtr != NULL)) + { + MemFreeAligned (myData.myDataPtr); + } + myData.myDataPtr = myData.myTopRowPtr = NULL; + myIsOwnPointer = true; + myData.mySizeX = myData.mySizeY = myData.mySizeRowBytes = 0; + setFormat (thePixelFormat); + myData.myTopToDown = 1; } // ======================================================================= @@ -435,64 +230,130 @@ Quantity_Color Image_PixMap::PixelColor (const Standard_Integer theX, const Standard_Integer theY, Quantity_Parameter& theAlpha) const { - Standard_Integer aScanlineId = myImage->getHeight() - theY - 1; - if (theX < 0 || (unsigned int )theX >= (unsigned int )myImage->getWidth() || - theY < 0 || (unsigned int )theY >= (unsigned int )myImage->getHeight()) + if (IsEmpty() || + theX < 0 || (Standard_Size )theX >= myData.mySizeX || + theY < 0 || (Standard_Size )theY >= myData.mySizeY) { theAlpha = 0.0; // transparent return Quantity_Color (0.0, 0.0, 0.0, Quantity_TOC_RGB); } -#ifdef HAVE_FREEIMAGE - else if (myImage->getImageType() == FIT_BITMAP) - { - RGBQUAD aValue; memset (&aValue, 0, sizeof(aValue)); - myImage->getPixelColor (theX, aScanlineId, &aValue); - theAlpha = (myImage->getColorType() == FIC_RGBALPHA) ? (Standard_Real (aValue.rgbReserved) / 255.0) : 1.0; - return Quantity_Color (Standard_Real (aValue.rgbRed) / 255.0, - Standard_Real (aValue.rgbGreen) / 255.0, - Standard_Real (aValue.rgbBlue) / 255.0, - Quantity_TOC_RGB); - } - else + + switch (myImgFormat) { - switch (myImage->getImageType()) + case ImgGrayF: + { + const Standard_ShortReal& aPixel = Value (theY, theX); + theAlpha = 1.0; // opaque + return Quantity_Color (Quantity_Parameter (Standard_Real (aPixel)), + Quantity_Parameter (Standard_Real (aPixel)), + Quantity_Parameter (Standard_Real (aPixel)), + Quantity_TOC_RGB); + break; + } + case ImgRGBAF: + { + const Image_ColorRGBAF& aPixel = Value (theY, theX); + theAlpha = aPixel.a(); + return Quantity_Color (Quantity_Parameter (aPixel.r()), + Quantity_Parameter (aPixel.g()), + Quantity_Parameter (aPixel.b()), + Quantity_TOC_RGB); + } + case ImgBGRAF: + { + const Image_ColorBGRAF& aPixel = Value (theY, theX); + theAlpha = aPixel.a(); + return Quantity_Color (Quantity_Parameter (aPixel.r()), + Quantity_Parameter (aPixel.g()), + Quantity_Parameter (aPixel.b()), + Quantity_TOC_RGB); + } + case ImgRGBF: + { + const Image_ColorRGBF& aPixel = Value (theY, theX); + theAlpha = 1.0; // opaque + return Quantity_Color (Quantity_Parameter (aPixel.r()), + Quantity_Parameter (aPixel.g()), + Quantity_Parameter (aPixel.b()), + Quantity_TOC_RGB); + } + case ImgBGRF: { - case FIT_FLOAT: - { - float* aScanLine = (float* )myImage->getScanLine (aScanlineId); - Quantity_Parameter aValue = Quantity_Parameter (aScanLine[theX]); - theAlpha = 1.0; // opaque - return Quantity_Color (aValue, aValue, aValue, Quantity_TOC_RGB); - } - case FIT_RGBF: - { - FIRGBF* aScanLine = (FIRGBF* )myImage->getScanLine (aScanlineId); - FIRGBF* aPixel = &aScanLine[theX]; - theAlpha = 1.0; // opaque - return Quantity_Color (Quantity_Parameter (aPixel->red), - Quantity_Parameter (aPixel->green), - Quantity_Parameter (aPixel->blue), - Quantity_TOC_RGB); - } - case FIT_RGBAF: - { - FIRGBAF* aScanLine = (FIRGBAF* )myImage->getScanLine (aScanlineId); - FIRGBAF* aPixel = &aScanLine[theX]; - theAlpha = aPixel->alpha; - return Quantity_Color (Quantity_Parameter (aPixel->red), - Quantity_Parameter (aPixel->green), - Quantity_Parameter (aPixel->blue), - Quantity_TOC_RGB); - } - default: - { - // not supported image type - theAlpha = 0.0; // transparent - return Quantity_Color (0.0, 0.0, 0.0, Quantity_TOC_RGB); - } + const Image_ColorBGRF& aPixel = Value (theY, theX); + theAlpha = 1.0; // opaque + return Quantity_Color (Quantity_Parameter (aPixel.r()), + Quantity_Parameter (aPixel.g()), + Quantity_Parameter (aPixel.b()), + Quantity_TOC_RGB); + } + case ImgRGBA: + { + const Image_ColorRGBA& aPixel = Value (theY, theX); + theAlpha = Standard_Real (aPixel.a()) / 255.0; + return Quantity_Color (Quantity_Parameter (Standard_Real (aPixel.r()) / 255.0), + Quantity_Parameter (Standard_Real (aPixel.g()) / 255.0), + Quantity_Parameter (Standard_Real (aPixel.b()) / 255.0), + Quantity_TOC_RGB); + } + case ImgBGRA: + { + const Image_ColorBGRA& aPixel = Value (theY, theX); + theAlpha = Standard_Real (aPixel.a()) / 255.0; + return Quantity_Color (Quantity_Parameter (Standard_Real (aPixel.r()) / 255.0), + Quantity_Parameter (Standard_Real (aPixel.g()) / 255.0), + Quantity_Parameter (Standard_Real (aPixel.b()) / 255.0), + Quantity_TOC_RGB); + } + case ImgRGB32: + { + const Image_ColorRGB32& aPixel = Value (theY, theX); + theAlpha = 1.0; // opaque + return Quantity_Color (Quantity_Parameter (Standard_Real (aPixel.r()) / 255.0), + Quantity_Parameter (Standard_Real (aPixel.g()) / 255.0), + Quantity_Parameter (Standard_Real (aPixel.b()) / 255.0), + Quantity_TOC_RGB); + } + case ImgBGR32: + { + const Image_ColorBGR32& aPixel = Value (theY, theX); + theAlpha = 1.0; // opaque + return Quantity_Color (Quantity_Parameter (Standard_Real (aPixel.r()) / 255.0), + Quantity_Parameter (Standard_Real (aPixel.g()) / 255.0), + Quantity_Parameter (Standard_Real (aPixel.b()) / 255.0), + Quantity_TOC_RGB); + } + case ImgRGB: + { + const Image_ColorRGB& aPixel = Value (theY, theX); + theAlpha = 1.0; // opaque + return Quantity_Color (Quantity_Parameter (Standard_Real (aPixel.r()) / 255.0), + Quantity_Parameter (Standard_Real (aPixel.g()) / 255.0), + Quantity_Parameter (Standard_Real (aPixel.b()) / 255.0), + Quantity_TOC_RGB); + } + case ImgBGR: + { + const Image_ColorBGR& aPixel = Value (theY, theX); + theAlpha = 1.0; // opaque + return Quantity_Color (Quantity_Parameter (Standard_Real (aPixel.r()) / 255.0), + Quantity_Parameter (Standard_Real (aPixel.g()) / 255.0), + Quantity_Parameter (Standard_Real (aPixel.b()) / 255.0), + Quantity_TOC_RGB); + } + case ImgGray: + { + const Standard_Byte& aPixel = Value (theY, theX); + theAlpha = 1.0; // opaque + return Quantity_Color (Quantity_Parameter (Standard_Real (aPixel) / 255.0), + Quantity_Parameter (Standard_Real (aPixel) / 255.0), + Quantity_Parameter (Standard_Real (aPixel) / 255.0), + Quantity_TOC_RGB); + } + default: + { + // not supported image type + theAlpha = 0.0; // transparent + return Quantity_Color (0.0, 0.0, 0.0, Quantity_TOC_RGB); } } -#else - return myImage->getPixelColor (theX, aScanlineId, theAlpha); -#endif } diff --git a/src/Image/Image_PixMap.hxx b/src/Image/Image_PixMap.hxx new file mode 100644 index 0000000000..e0d2a41dd0 --- /dev/null +++ b/src/Image/Image_PixMap.hxx @@ -0,0 +1,294 @@ +// Created on: 2012-07-18 +// Created by: Kirill GAVRILOV +// Copyright (c) 2012 OPEN CASCADE SAS +// +// The content of this file is subject to the Open CASCADE Technology Public +// License Version 6.5 (the "License"). You may not use the content of this file +// except in compliance with the License. Please obtain a copy of the License +// at http://www.opencascade.org and read it completely before using this file. +// +// The Initial Developer of the Original Code is Open CASCADE S.A.S., having its +// main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France. +// +// The Original Code and all software distributed under the License is +// distributed on an "AS IS" basis, without warranty of any kind, and the +// Initial Developer hereby disclaims all such warranties, including without +// limitation, any warranties of merchantability, fitness for a particular +// purpose or non-infringement. Please see the License for the specific terms +// and conditions governing the rights and limitations under the License. + +#ifndef _Image_PixMap_H__ +#define _Image_PixMap_H__ + +#include +#include +#include + +//! Class represents packed image plane. +class Image_PixMap : public Standard_Transient +{ + +public: + + //! This enumeration define packed image plane formats + typedef enum tagFormat { + ImgUNKNOWN = 0, //!< unsupported or unknown format + ImgGray = 1, //!< 1 byte per pixel + ImgRGB, //!< 3 bytes packed RGB image plane + ImgBGR, //!< same as RGB but with different components order + ImgRGB32, //!< 4 bytes packed RGB image plane (1 extra byte for alignment, may have undefined value) + ImgBGR32, //!< same as RGB but with different components order + ImgRGBA, //!< 4 bytes packed RGBA image plane + ImgBGRA, //!< same as RGBA but with different components order + ImgGrayF, //!< 1 float (4-bytes) per pixel (1-component plane) + ImgRGBF, //!< 3 floats (12-bytes) RGB image plane + ImgBGRF, //!< same as RGBF but with different components order + ImgRGBAF, //!< 4 floats (16-bytes) RGBA image plane + ImgBGRAF, //!< same as RGBAF but with different components order + } ImgFormat; + + //! Determine Big-Endian at runtime + static inline bool IsBigEndianHost() + { + union { int myInt; char myChar[sizeof(int)]; } aUnion; + aUnion.myInt = 1; + return !aUnion.myChar[0]; + } + +public: // high-level API + + inline ImgFormat Format() const + { + return myImgFormat; + } + + //! @return image width in pixels + inline Standard_Size Width() const + { + return myData.mySizeX; + } + + //! @return image height in pixels + inline Standard_Size Height() const + { + return myData.mySizeY; + } + + //! @return image width in pixels + inline Standard_Size SizeX() const + { + return myData.mySizeX; + } + + //! @return image height in pixels + inline Standard_Size SizeY() const + { + return myData.mySizeY; + } + + //! @return width / height. + inline Standard_Real Ratio() const + { + return (myData.mySizeY > 0) ? (Standard_Real(myData.mySizeX) / Standard_Real(myData.mySizeY)) : 1.0; + } + + //! @return true if data is NULL. + bool IsEmpty() const + { + return myData.myDataPtr == NULL; + } + + //! Empty constructor. Initialize the NULL image plane. + Standard_EXPORT Image_PixMap(); + + //! Destructor + Standard_EXPORT virtual ~Image_PixMap(); + + //! Returns the pixel color. This function is relatively slow. + //! @param theX - column index from left + //! @param theY - row index from top + //! @return the pixel color + inline Quantity_Color PixelColor (const Standard_Integer theX, + const Standard_Integer theY) const + { + Quantity_Parameter aDummy; + return PixelColor (theX, theY, aDummy); + } + + //! Returns the pixel color. This function is relatively slow. + //! theAlpha argument is set to color intensity (0 - transparent, 1 - opaque) + Standard_EXPORT Quantity_Color PixelColor (const Standard_Integer theX, + const Standard_Integer theY, + Quantity_Parameter& theAlpha) const; + + //! Initialize image plane as wrapper over alien data. + //! Data will not be copied! Notice that caller should ensure + //! that data pointer will not be released during this wrapper lifetime. + //! You may call InitCopy() to perform data copying. + Standard_EXPORT virtual bool InitWrapper (ImgFormat thePixelFormat, + Standard_Byte* theDataPtr, + const Standard_Size theSizeX, + const Standard_Size theSizeY, + const Standard_Size theSizeRowBytes = 0); + + //! Initialize image plane with required dimensions. + //! Memory will be left uninitialized (performance trick). + Standard_EXPORT virtual bool InitTrash (ImgFormat thePixelFormat, + const Standard_Size theSizeX, + const Standard_Size theSizeY, + const Standard_Size theSizeRowBytes = 0); + + //! Initialize by copying data. + //! If you want to copy alien data you should create wrapper using InitWrapper() before. + Standard_EXPORT virtual bool InitCopy (const Image_PixMap& theCopy); + + //! Initialize image plane with required dimensions. + //! Buffer will be zeroed (black color for most formats). + Standard_EXPORT bool InitZero (ImgFormat thePixelFormat, + const Standard_Size theSizeX, + const Standard_Size theSizeY, + const Standard_Size theSizeRowBytes = 0, + const Standard_Byte theValue = 0); + + //! Method correctly deallocate internal buffer. + Standard_EXPORT virtual void Clear (ImgFormat thePixelFormat = ImgGray); + +public: // low-level API for batch-processing (pixels reading / comparison / modification) + + //! Returns true if image data stored from Top to the Down (default). + //! Some external APIs can return bottom-up data instead + //! (topmost scanlines starts from the bottom in memory). + //! Notice that access methods within this class automatically + //! convert input row-index to apply this flag! + //! You should use this flag only if interconnect with alien APIs and buffers. + //! @return true if image data is top-down. + inline bool IsTopDown() const + { + return myData.myTopToDown == 1; + } + + //! Setup scanlines order in memory - top-down or bottom-up. + //! Drawers should explicitly specify this value if current state IsTopDown() was ignored! + //! @param theIsTopDown - top-down flag. + inline void SetTopDown (bool theIsTopDown) + { + myData.myTopToDown = (theIsTopDown ? 1 : Standard_Size(-1)); + setTopDown(); + } + + //! Returns +1 if scanlines ordered in Top->Down order in memory and -1 otherwise. + //! @return scanline increment for Top->Down iteration + inline Standard_Size TopDownInc() const + { + return myData.myTopToDown; + } + + //! @return data pointer for low-level operations (copying entire buffer, parsing with extra tools etc.). + inline const Standard_Byte* Data() const + { + return myData.myDataPtr; + } + + //! @return data pointer for low-level operations (copying entire buffer, parsing with extra tools etc.). + inline Standard_Byte* ChangeData() + { + return myData.myDataPtr; + } + + //! @return data pointer to requested row (first column). + inline const Standard_Byte* Row (const Standard_Size theRow) const + { + return myData.Row (theRow); + } + + //! @return data pointer to requested row (first column). + inline Standard_Byte* ChangeRow (const Standard_Size theRow) + { + return myData.ChangeRow (theRow); + } + + //! @return bytes reserved for one pixel (may include extra bytes for alignment). + inline Standard_Size SizePixelBytes() const + { + return myData.mySizeBPP; + } + + //! @return bytes reserved for one pixel (may include extra bytes for alignment). + static Standard_Size SizePixelBytes (const Image_PixMap::ImgFormat thePixelFormat); + + //! @return bytes reserved per row. + //! Could be larger than needed to store packed row (extra bytes for alignment etc.). + inline Standard_Size SizeRowBytes() const + { + return myData.mySizeRowBytes; + } + + //! @return the extra bytes in the row. + inline Standard_Size RowExtraBytes() const + { + return myData.mySizeRowBytes - myData.mySizeX * myData.mySizeBPP; + } + + //! Compute the maximal row alignment for current row size. + //! @return maximal row alignment in bytes (up to 16 bytes). + inline Standard_Size MaxRowAligmentBytes() const + { + return myData.MaxRowAligmentBytes(); + } + + inline Standard_Size SizeBytes() const + { + return myData.SizeBytes(); + } + + //! Access image buffer for write/read operations with specified color type. + template + inline Image_PixMapData& EditData() + { + return *(Image_PixMapData* )&myData; + } + + //! Access image buffer for read operations with specified color type. + template + inline const Image_PixMapData& ReadData() const + { + return *(Image_PixMapData* )&myData; + } + + //! Access image pixel with specified color type. + template + inline const ColorType_t& Value (const Standard_Size theRow, + const Standard_Size theCol) const + { + return ((Image_PixMapData* )&myData)->Value (theRow, theCol); + } + +protected: + + //! Setup pixel format + Standard_EXPORT void setFormat (ImgFormat thePixelFormat); + + //! Auxiliary method to setup myTopRowPtr + Standard_EXPORT void setTopDown(); + +protected: + + Image_PixMapData myData; + ImgFormat myImgFormat; //!< pixel format + bool myIsOwnPointer; //!< if data was allocated by this class - flag is true + +private: + + //! Copying allowed only within Handles + Image_PixMap (const Image_PixMap& ); + Image_PixMap& operator= (const Image_PixMap& ); + +public: + + DEFINE_STANDARD_RTTI(Image_PixMap) // Type definition + +}; + +DEFINE_STANDARD_HANDLE(Image_PixMap, Standard_Transient) + +#endif // _Image_PixMap_H__ diff --git a/src/Image/Image_PixMapData.hxx b/src/Image/Image_PixMapData.hxx new file mode 100644 index 0000000000..f0ee720239 --- /dev/null +++ b/src/Image/Image_PixMapData.hxx @@ -0,0 +1,113 @@ +// Created on: 2012-07-18 +// Created by: Kirill GAVRILOV +// Copyright (c) 2012 OPEN CASCADE SAS +// +// The content of this file is subject to the Open CASCADE Technology Public +// License Version 6.5 (the "License"). You may not use the content of this file +// except in compliance with the License. Please obtain a copy of the License +// at http://www.opencascade.org and read it completely before using this file. +// +// The Initial Developer of the Original Code is Open CASCADE S.A.S., having its +// main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France. +// +// The Original Code and all software distributed under the License is +// distributed on an "AS IS" basis, without warranty of any kind, and the +// Initial Developer hereby disclaims all such warranties, including without +// limitation, any warranties of merchantability, fitness for a particular +// purpose or non-infringement. Please see the License for the specific terms +// and conditions governing the rights and limitations under the License. + +#ifndef _Image_PixMapData_H__ +#define _Image_PixMapData_H__ + +#include + +//! POD template structure to access image buffer +template +struct Image_PixMapData +{ + + //! @return data pointer for low-level operations (copying entire buffer, parsing with extra tools etc.). + inline const ColorType_t* Data() const + { + return (const ColorType_t* )myDataPtr; + } + + //! @return data pointer for low-level operations (copying entire buffer, parsing with extra tools etc.). + inline ColorType_t* ChangeData() + { + return (ColorType_t* )myDataPtr; + } + + //! @return data pointer to requested row (first column). + inline const ColorType_t* Row (const Standard_Size theRow) const + { + return (ColorType_t* )(myTopRowPtr + mySizeRowBytes * theRow * myTopToDown); + } + + //! @return data pointer to requested row (first column). + inline ColorType_t* ChangeRow (const Standard_Size theRow) + { + return (ColorType_t* )(myTopRowPtr + mySizeRowBytes * theRow * myTopToDown); + } + + //! @return data pointer to requested position. + inline const ColorType_t& Value (const Standard_Size theRow, + const Standard_Size theCol) const + { + return *(const ColorType_t* )(myTopRowPtr + mySizeRowBytes * theRow * myTopToDown + mySizeBPP * theCol); + } + + //! @return data pointer to requested position. + inline ColorType_t& ChangeValue (const Standard_Size theRow, + const Standard_Size theCol) + { + return *(ColorType_t* )(myTopRowPtr + mySizeRowBytes * theRow * myTopToDown + mySizeBPP * theCol); + } + + //! Compute the maximal row alignment for current row size. + //! @return maximal row alignment in bytes (up to 16 bytes). + inline Standard_Size MaxRowAligmentBytes() const + { + Standard_Size anAlignment = 2; + for (; anAlignment <= 16; anAlignment <<= 1) + { + if ((mySizeRowBytes % anAlignment) != 0 || (Standard_Size(myDataPtr) % anAlignment) != 0) + { + return (anAlignment >> 1); + } + } + return anAlignment; + } + + //! @return bytes allocated for the whole image plane. + inline Standard_Size SizeBytes() const + { + return mySizeRowBytes * mySizeY; + } + + //! @return image width in pixels + inline Standard_Size SizeX() const + { + return mySizeX; + } + + //! @return image height in pixels + inline Standard_Size SizeY() const + { + return mySizeY; + } + +public: + + Standard_Byte* myDataPtr; //!< pointer to the data + Standard_Byte* myTopRowPtr; //!< pointer to the topmost row (depending on scanlines order in memory) + Standard_Size mySizeBPP; //!< bytes per pixel + Standard_Size mySizeX; //!< width in pixels + Standard_Size mySizeY; //!< height in pixels + Standard_Size mySizeRowBytes; //!< number of bytes per line (in most cases equal to 3 * sizeX) + Standard_Size myTopToDown; //!< image scanlines direction in memory from Top to the Down + +}; + +#endif // _Image_PixMapData_H__ diff --git a/src/InterfaceGraphic/FILES b/src/InterfaceGraphic/FILES index da7204e664..93ca56a517 100755 --- a/src/InterfaceGraphic/FILES +++ b/src/InterfaceGraphic/FILES @@ -11,7 +11,6 @@ InterfaceGraphic_wntio.hxx InterfaceGraphic_cPrintf.cxx InterfaceGraphic_Palette.c InterfaceGraphic_PrimitiveArray.hxx -InterfaceGraphic_RawBufferData.hxx InterfaceGraphic_telem.hxx InterfaceGraphic_degeneration.hxx InterfaceGraphic_tgl_all.hxx diff --git a/src/InterfaceGraphic/InterfaceGraphic_RawBufferData.hxx b/src/InterfaceGraphic/InterfaceGraphic_RawBufferData.hxx deleted file mode 100644 index bff620e22e..0000000000 --- a/src/InterfaceGraphic/InterfaceGraphic_RawBufferData.hxx +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (c) 1991-1999 Matra Datavision -// Copyright (c) 1999-2012 OPEN CASCADE SAS -// -// The content of this file is subject to the Open CASCADE Technology Public -// License Version 6.5 (the "License"). You may not use the content of this file -// except in compliance with the License. Please obtain a copy of the License -// at http://www.opencascade.org and read it completely before using this file. -// -// The Initial Developer of the Original Code is Open CASCADE S.A.S., having its -// main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France. -// -// The Original Code and all software distributed under the License is -// distributed on an "AS IS" basis, without warranty of any kind, and the -// Initial Developer hereby disclaims all such warranties, including without -// limitation, any warranties of merchantability, fitness for a particular -// purpose or non-infringement. Please see the License for the specific terms -// and conditions governing the rights and limitations under the License. - -#ifndef INTERFACEGRAPHIC_RawBufferData_H -#define INTERFACEGRAPHIC_RawBufferData_H - -#include - -// Most items are from GLenum, but values not equal! -typedef enum -{ - TRGB, - TBGR, - TRGBA, - TBGRA, - TDepthComponent, - TRed, - TGreen, - TBlue, - TAlpha, -} TRawBufferDataFormat; - -typedef enum -{ - TUByte, - TFloat, -} TRawBufferDataType; - -struct TRawBufferData -{ - Standard_Integer widthPx; - Standard_Integer heightPx; - Standard_Integer rowAligmentBytes; - TRawBufferDataFormat format; - TRawBufferDataType type; - Standard_Address dataPtr; -}; - -#endif /* INTERFACEGRAPHIC_RawBufferData_H */ diff --git a/src/OpenGl/OpenGl_GraphicDriver.hxx b/src/OpenGl/OpenGl_GraphicDriver.hxx index 01f02b98be..b704436e20 100644 --- a/src/OpenGl/OpenGl_GraphicDriver.hxx +++ b/src/OpenGl/OpenGl_GraphicDriver.hxx @@ -32,7 +32,6 @@ #include #include #include -#include #include #include @@ -69,6 +68,7 @@ #include #include #include +#include #include class TColStd_Array1OfInteger; @@ -82,6 +82,7 @@ class Graphic3d_Vertex; class Aspect_Array1OfEdge; class TCollection_ExtendedString; class AlienImage_AlienImage; +class Image_PixMap; class TColStd_HArray1OfReal; class Handle(OpenGl_View); class Handle(OpenGl_Workspace); @@ -262,7 +263,9 @@ public: //! Remove offscreen FBO
Standard_EXPORT void FBORelease (const Graphic3d_CView& view, Graphic3d_PtrFrameBuffer& fboPtr); //! Dump active rendering buffer into specified memory buffer.
- Standard_EXPORT Standard_Boolean BufferDump (const Graphic3d_CView& view, Image_CRawBufferData& buffer); + Standard_EXPORT Standard_Boolean BufferDump (const Graphic3d_CView& theCView, + Image_PixMap& theImage, + const Graphic3d_BufferType& theBufferType); Standard_EXPORT void SetGLLightEnabled (const Graphic3d_CView& view,const Standard_Boolean isEnabled) const; Standard_EXPORT Standard_Boolean IsGLLightEnabled (const Graphic3d_CView& view) const; //! Clear visualization data in graphical driver and stop
diff --git a/src/OpenGl/OpenGl_GraphicDriver_7.cxx b/src/OpenGl/OpenGl_GraphicDriver_7.cxx index d67a84f327..b7e6414e71 100755 --- a/src/OpenGl/OpenGl_GraphicDriver_7.cxx +++ b/src/OpenGl/OpenGl_GraphicDriver_7.cxx @@ -284,72 +284,88 @@ void OpenGl_GraphicDriver::FBOChangeViewport (const Graphic3d_CView& , aFrameBuffer->ChangeViewport (theWidth, theHeight); } -// OpenGL 1.2 stuff -#ifndef GL_BGR - #define GL_BGR 0x80E0 -#endif -#ifndef GL_BGRA - #define GL_BGRA 0x80E1 -#endif - -static inline GLenum TFormatToGLEnum (const TRawBufferDataFormat theTFormat) -{ - switch (theTFormat) - { - case TRGB: return GL_RGB; - case TBGR: return GL_BGR; - case TRGBA: return GL_RGBA; - case TBGRA: return GL_BGRA; - case TDepthComponent: return GL_DEPTH_COMPONENT; - case TRed: return GL_RED; - case TGreen: return GL_GREEN; - case TBlue: return GL_BLUE; - case TAlpha: return GL_ALPHA; - default: return 0; - } -} - -static inline GLenum TTypeToGLEnum (const TRawBufferDataType theTType) +inline bool getDataFormat (const Image_PixMap& theData, + GLenum& thePixelFormat, + GLenum& theDataType) { - switch (theTType) + thePixelFormat = GL_RGB; + theDataType = GL_UNSIGNED_BYTE; + switch (theData.Format()) { - case TUByte: return GL_UNSIGNED_BYTE; - case TFloat: return GL_FLOAT; - default: return 0; + case Image_PixMap::ImgGray: + thePixelFormat = GL_DEPTH_COMPONENT; + theDataType = GL_UNSIGNED_BYTE; + return true; + case Image_PixMap::ImgRGB: + thePixelFormat = GL_RGB; + theDataType = GL_UNSIGNED_BYTE; + return true; + case Image_PixMap::ImgBGR: + thePixelFormat = GL_BGR; + theDataType = GL_UNSIGNED_BYTE; + return true; + case Image_PixMap::ImgRGBA: + case Image_PixMap::ImgRGB32: + thePixelFormat = GL_RGBA; + theDataType = GL_UNSIGNED_BYTE; + return true; + case Image_PixMap::ImgBGRA: + case Image_PixMap::ImgBGR32: + thePixelFormat = GL_BGRA; + theDataType = GL_UNSIGNED_BYTE; + return true; + case Image_PixMap::ImgGrayF: + thePixelFormat = GL_DEPTH_COMPONENT; + theDataType = GL_FLOAT; + return true; + case Image_PixMap::ImgRGBF: + thePixelFormat = GL_RGB; + theDataType = GL_FLOAT; + return true; + case Image_PixMap::ImgBGRF: + thePixelFormat = GL_BGR; + theDataType = GL_FLOAT; + return true; + case Image_PixMap::ImgRGBAF: + thePixelFormat = GL_RGBA; + theDataType = GL_FLOAT; + return true; + case Image_PixMap::ImgBGRAF: + thePixelFormat = GL_BGRA; + theDataType = GL_FLOAT; + return true; + default: + return false; } } -Standard_Boolean OpenGl_GraphicDriver::BufferDump (const Graphic3d_CView& ACView, Image_CRawBufferData& theBuffer) +Standard_Boolean OpenGl_GraphicDriver::BufferDump (const Graphic3d_CView& theCView, + Image_PixMap& theImage, + const Graphic3d_BufferType& theBufferType) { - const OpenGl_CView *aCView = (const OpenGl_CView *)ACView.ptrView; - if (aCView) - return aCView->WS->BufferDump((OpenGl_FrameBuffer *)ACView.ptrFBO,theBuffer); + const OpenGl_CView* aCView = (const OpenGl_CView* )theCView.ptrView; + return (aCView != NULL) && aCView->WS->BufferDump ((OpenGl_FrameBuffer* )theCView.ptrFBO, theImage, theBufferType); return Standard_False; } -Standard_Boolean OpenGl_Workspace::BufferDump (OpenGl_FrameBuffer *theFBOPtr, Image_CRawBufferData& theBuffer) +Standard_Boolean OpenGl_Workspace::BufferDump (OpenGl_FrameBuffer* theFBOPtr, + Image_PixMap& theImage, + const Graphic3d_BufferType& theBufferType) { - GLenum aFormat = TFormatToGLEnum (theBuffer.format); - GLenum aType = TTypeToGLEnum (theBuffer.type); - - // safe checks - if (aFormat == 0 || aType == 0 || - theBuffer.widthPx == 0 || theBuffer.heightPx == 0 || - theBuffer.dataPtr == NULL) + GLenum aFormat, aType; + if (theImage.IsEmpty() + || !getDataFormat (theImage, aFormat, aType) + || ((theBufferType == Graphic3d_BT_Depth) && (aFormat != GL_DEPTH_COMPONENT)) + || !Activate()) { return Standard_False; } - // activate OpenGL context - if (!Activate()) - return Standard_False; - // bind FBO if used - OpenGl_FrameBuffer* aFrameBuffer = theFBOPtr; GLint aReadBufferPrev = GL_BACK; - if (aFrameBuffer != NULL && aFrameBuffer->IsValid()) + if (theFBOPtr != NULL && theFBOPtr->IsValid()) { - aFrameBuffer->BindBuffer (GetGlContext()); + theFBOPtr->BindBuffer (GetGlContext()); } else { @@ -361,19 +377,30 @@ Standard_Boolean OpenGl_Workspace::BufferDump (OpenGl_FrameBuffer *theFBOPtr, Im GLint anAlignBack = 1; glGetIntegerv (GL_PACK_ALIGNMENT, &anAlignBack); - if (theBuffer.rowAligmentBytes == 0) + GLint anExtraBytes = (GLint )theImage.RowExtraBytes(); + GLint anAligment = Min (GLint(theImage.MaxRowAligmentBytes()), 8); // limit to 8 bytes for OpenGL + glPixelStorei (GL_PACK_ALIGNMENT, anAligment); + + if (anExtraBytes >= anAligment) + { + // copy row by row + for (Standard_Size aRow = 0; aRow < theImage.SizeY(); ++aRow) + { + glReadPixels (0, GLint(aRow), GLsizei (theImage.SizeX()), 1, aFormat, aType, theImage.ChangeRow (aRow)); + } + } + else { - theBuffer.rowAligmentBytes = 1; + // read pixels + glReadPixels (0, 0, GLsizei (theImage.SizeX()), GLsizei (theImage.SizeY()), aFormat, aType, theImage.ChangeData()); + theImage.SetTopDown (false); // image bottom-up in OpenGL } - glPixelStorei (GL_PACK_ALIGNMENT, theBuffer.rowAligmentBytes); - // read pixels - glReadPixels (0, 0, theBuffer.widthPx, theBuffer.heightPx, aFormat, aType, (GLvoid* )theBuffer.dataPtr); glPixelStorei (GL_PACK_ALIGNMENT, anAlignBack); - if (aFrameBuffer != NULL && aFrameBuffer->IsValid()) + if (theFBOPtr != NULL && theFBOPtr->IsValid()) { - aFrameBuffer->UnbindBuffer (GetGlContext()); + theFBOPtr->UnbindBuffer (GetGlContext()); } else { diff --git a/src/OpenGl/OpenGl_Workspace.hxx b/src/OpenGl/OpenGl_Workspace.hxx index b927c46b0d..6e9d569a9c 100644 --- a/src/OpenGl/OpenGl_Workspace.hxx +++ b/src/OpenGl/OpenGl_Workspace.hxx @@ -33,7 +33,7 @@ #include #include #include -#include +#include #include #include @@ -53,6 +53,7 @@ class OpenGl_AspectMarker; class OpenGl_AspectText; class OpenGl_FrameBuffer; class OpenGl_Structure; +class Image_PixMap; //! Reprepsents window with GL context. //! Provides methods to render primitives and maintan GL state. @@ -127,7 +128,9 @@ public: Graphic3d_PtrFrameBuffer FBOCreate (const Standard_Integer theWidth, const Standard_Integer theHeight); void FBORelease (Graphic3d_PtrFrameBuffer theFBOPtr); - Standard_Boolean BufferDump (OpenGl_FrameBuffer *theFBOPtr, Image_CRawBufferData& theBuffer); + Standard_Boolean BufferDump (OpenGl_FrameBuffer* theFBOPtr, + Image_PixMap& theImage, + const Graphic3d_BufferType& theBufferType); void UseTransparency (const Standard_Boolean theFlag); Standard_Boolean& UseZBuffer() { return myUseZBuffer; } diff --git a/src/QADraw/QADraw.cxx b/src/QADraw/QADraw.cxx index 022a3ccd27..cd0c279b30 100755 --- a/src/QADraw/QADraw.cxx +++ b/src/QADraw/QADraw.cxx @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include #include #include @@ -426,19 +426,18 @@ static Standard_Integer QAvzfit(Draw_Interpretor& di, Standard_Integer /*argc*/, return 0; } -Handle(TColStd_HSequenceOfReal) GetColorOfPixel (const Handle(Aspect_PixMap) theImage, +Handle(TColStd_HSequenceOfReal) GetColorOfPixel (const Image_PixMap& theImage, const Standard_Integer theCoordinateX, const Standard_Integer theCoordinateY, const Standard_Integer theRadius) { Handle(TColStd_HSequenceOfReal) aSeq = new TColStd_HSequenceOfReal(); - if (theImage.IsNull()) { + if (theImage.IsEmpty()) { std::cerr << "The image is null.\n"; return aSeq; } - Standard_Integer aWidth = 0; - Standard_Integer anHeight = 0; - theImage->Size (aWidth, anHeight); + Standard_Integer aWidth = (Standard_Integer )theImage.SizeX(); + Standard_Integer anHeight = (Standard_Integer )theImage.SizeY(); Quantity_Color aColorTmp; for (Standard_Integer anXIter = theCoordinateX - theRadius; @@ -456,7 +455,7 @@ Handle(TColStd_HSequenceOfReal) GetColorOfPixel (const Handle(Aspect_PixMap) the continue; } // Image_PixMap stores image upside-down in memory! - aColorTmp = theImage->PixelColor (anXIter, anYIter); + aColorTmp = theImage.PixelColor (anXIter, anYIter); aSeq->Append (aColorTmp.Red()); aSeq->Append (aColorTmp.Green()); aSeq->Append (aColorTmp.Blue()); @@ -482,8 +481,8 @@ static Standard_Integer QAAISGetPixelColor (Draw_Interpretor& di, Standard_Integ Standard_Integer QAAISXWindowSize_X = 0; Standard_Integer QAAISXWindowSize_Y = 0; QAAISWindow->Size(QAAISXWindowSize_X, QAAISXWindowSize_Y); - Standard_ShortReal QAAISCoordinateX = atoi (argv [1]); - Standard_ShortReal QAAISCoordinateY = atoi (argv [2]); + Standard_ShortReal QAAISCoordinateX = atof (argv [1]); + Standard_ShortReal QAAISCoordinateY = atof (argv [2]); Standard_ShortReal QAAISColorRED_V = 0; Standard_ShortReal QAAISColorGRN_V = 0; @@ -504,9 +503,9 @@ static Standard_Integer QAAISGetPixelColor (Draw_Interpretor& di, Standard_Integ aRadius=0; } - Handle(TColStd_HSequenceOfReal) aSeq = GetColorOfPixel (QAAISView->ToPixMap (QAAISXWindowSize_X, QAAISXWindowSize_Y, Image_TOI_RGB), - QAAISCoordinateX, QAAISCoordinateY, - aRadius); + Image_PixMap anImage; + QAAISView->ToPixMap (anImage, QAAISXWindowSize_X, QAAISXWindowSize_Y); + Handle(TColStd_HSequenceOfReal) aSeq = GetColorOfPixel (anImage, QAAISCoordinateX, QAAISCoordinateY, aRadius); cout << "Length = " << aSeq->Length() << endl; Standard_Boolean IsNotEqual = Standard_True; @@ -696,6 +695,7 @@ static Standard_Integer QAAISGetViewCharac (Draw_Interpretor& di, Standard_Integ di << "Proj on X : " << QAAISViewProjX << "; on Y: " << QAAISViewProjY << "; on Z: " << QAAISViewProjZ << "\n"; di << "Up on X : " << QAAISViewUpX << "; on Y: " << QAAISViewUpY << "; on Z: " << QAAISViewUpZ << "\n"; di << "At on X : " << QAAISViewAtX << "; on Y: " << QAAISViewAtY << "; on Z: " << QAAISViewAtZ << "\n"; + return 0; } static Standard_Integer QAAISSetViewCharac (Draw_Interpretor& di, Standard_Integer argc, const char ** argv) @@ -737,7 +737,7 @@ static Standard_Integer QAAISGetColorCoord (Draw_Interpretor& di, Standard_Integ di << "Usage : " << argv[0] << " [3d|2d]" << "\n"; return 1; } - Handle (Aspect_Window) QAAISWindow; + Handle(Xw_Window) QAAISWindow; Standard_Boolean is3d = 1; @@ -748,7 +748,7 @@ static Standard_Integer QAAISGetColorCoord (Draw_Interpretor& di, Standard_Integ di << "You must initialize AISViewer before this command." << "\n"; return 1; } - QAAISWindow = QAAIS_MainView -> V3d_View::Window (); + QAAISWindow = Handle(Xw_Window)::DownCast (QAAIS_MainView->V3d_View::Window()); is3d = 1; } @@ -758,7 +758,7 @@ static Standard_Integer QAAISGetColorCoord (Draw_Interpretor& di, Standard_Integ di << "You must initialize AIS 2D Viewer before this command." << "\n"; return 1; } - QAAISWindow = V->Driver()->Window(); + QAAISWindow = Handle(Xw_Window)::DownCast (V->Driver()->Window()); is3d = 0; } @@ -795,19 +795,20 @@ static Standard_Integer QAAISGetColorCoord (Draw_Interpretor& di, Standard_Integ const char **argvvv = (const char **) bufff; while ( is3d ? ViewerMainLoop (argccc, argvvv) : ViewerMainLoop2d (argccc, argvvv)) { Handle(TColStd_HSequenceOfReal) aSeq; + Image_PixMap anImage; if(is3d) { ViewerTest::GetMousePosition (QAAIS_MousePoint_X, QAAIS_MousePoint_Y); Handle (V3d_View) QAAIS_MainView = ViewerTest::CurrentView(); - aSeq = GetColorOfPixel (QAAIS_MainView->ToPixMap (QAAIS_WindowSize_X, QAAIS_WindowSize_Y, Image_TOI_RGB), - QAAIS_MousePoint_X, QAAIS_MousePoint_Y, 0); + QAAIS_MainView->ToPixMap (anImage, QAAIS_WindowSize_X, QAAIS_WindowSize_Y); } else { Viewer2dTest::GetMousePosition (QAAIS_MousePoint_X, QAAIS_MousePoint_Y); - aSeq = GetColorOfPixel (QAAISWindow->ToPixMap(), - QAAIS_MousePoint_X, QAAIS_MousePoint_Y, 0); + QAAISWindow->ToPixMap (anImage); } + aSeq = GetColorOfPixel (anImage, QAAIS_MousePoint_X, QAAIS_MousePoint_Y, 0); + QAAIS_ColorRED = aSeq->Value(1); QAAIS_ColorGRN = aSeq->Value(2); QAAIS_ColorBLU = aSeq->Value(3); @@ -869,8 +870,13 @@ static int QAAISGetPixelColor2d (Draw_Interpretor& di, Standard_Integer argc, co di << "You must initialize AIS 2D Viewer before this command." << "\n"; return 1; } + // Get Color - Handle(Aspect_Window) QAAISWindow = V->Driver()->Window(); + #if (defined(_WIN32) || defined(__WIN32__)) + Handle(WNT_Window) QAAISWindow = Handle(WNT_Window)::DownCast (V->Driver()->Window()); + #else + Handle(Xw_Window) QAAISWindow = Handle(Xw_Window )::DownCast (V->Driver()->Window()); + #endif Standard_ShortReal aCoordinateX = atoi(argv[1]); Standard_ShortReal aCoordinateY = atoi(argv[2]); @@ -895,9 +901,9 @@ static int QAAISGetPixelColor2d (Draw_Interpretor& di, Standard_Integer argc, co aRadius=0; } - Handle(TColStd_HSequenceOfReal) aSeq = GetColorOfPixel (QAAISWindow->ToPixMap(), - aCoordinateX, aCoordinateY, - aRadius); + Image_PixMap anImage; + QAAISWindow->ToPixMap (anImage); + Handle(TColStd_HSequenceOfReal) aSeq = GetColorOfPixel (anImage, aCoordinateX, aCoordinateY, aRadius); Standard_Boolean IsNotEqual = Standard_True; Standard_Integer i; @@ -1041,7 +1047,7 @@ static int V2dPan (Draw_Interpretor& di, int argc, const char ** argv) di << "use 'v2dinit' command before " << argv[0] << "\n"; return -1; } - Viewer2dTest::CurrentView()->Pan(atof(argv[1]), atof(argv[2])); + Viewer2dTest::CurrentView()->Pan(atoi(argv[1]), atoi(argv[2])); return 0; } @@ -1242,6 +1248,7 @@ static int QA2dGetIndexes (Draw_Interpretor& di, int /*argc*/, const char ** arg di << "Available font indexes are " << aFontMin << " - " << aFontMax << "\n"; aWindowDriver->ColorBoundIndexs(aColorMin, aColorMax); di << "Available color indexes are " << aColorMin << " - " << aColorMax << "\n"; + return 0; } #if ! defined(WNT) diff --git a/src/V3d/V3d_View.cdl b/src/V3d/V3d_View.cdl index 6bcbaa4413..540697859c 100755 --- a/src/V3d/V3d_View.cdl +++ b/src/V3d/V3d_View.cdl @@ -125,7 +125,7 @@ uses Plotter from Graphic3d, Window from Aspect, PixMap from Image, - TypeOfImage from Image, + BufferType from Graphic3d, Background from Aspect, GradientBackground from Aspect, PlotterDriver from PlotMgt, @@ -1590,8 +1590,8 @@ is ---Purpose: dump the view Dump ( me: mutable; - theFile: CString from Standard; - theBufferType : TypeOfImage from Image = Image_TOI_RGB ) + theFile : CString from Standard; + theBufferType : BufferType from Graphic3d = Graphic3d_BT_RGB ) returns Boolean from Standard; ---Level: Public ---Purpose: dump the full contents of the view at the same @@ -1600,9 +1600,9 @@ is -- Returns FALSE when the dump has failed Dump ( me: mutable; - theFile : CString from Standard; - theFormat : FormatOfSheetPaper from Aspect; - theBufferType : TypeOfImage from Image = Image_TOI_RGB ) + theFile : CString from Standard; + theFormat : FormatOfSheetPaper from Aspect; + theBufferType : BufferType from Graphic3d = Graphic3d_BT_RGB ) returns Boolean from Standard; ---Level: Public ---Purpose: dump the full contents of the view with a @@ -1653,16 +1653,18 @@ is -- Warning: Works only under Windows. ToPixMap ( me : mutable; + theImage : in out PixMap from Image; theWidth : Integer from Standard; theHeight : Integer from Standard; - theBufferType : TypeOfImage from Image = Image_TOI_RGB; + theBufferType : BufferType from Graphic3d = Graphic3d_BT_RGB; theForceCentered : Boolean from Standard = Standard_True ) - returns PixMap from Image; + returns Boolean from Standard; ---Level : Public ---Purpose : dump the full contents of the view -- to a pixmap of pixel size * and -- buffer type . If is true -- view scene will be centered. + -- Pixmap will be automatically (re)allocated when needed. SetProjModel( me : mutable; amOdel: TypeOfProjectionModel from V3d = V3d_TPM_SCREEN ) diff --git a/src/V3d/V3d_View.cxx b/src/V3d/V3d_View.cxx index fab3967484..a6b0e526f6 100755 --- a/src/V3d/V3d_View.cxx +++ b/src/V3d/V3d_View.cxx @@ -158,7 +158,7 @@ To solve the problem (for lack of a better solution) I make 2 passes. #include #include #include -#include +#include #include #include #include @@ -3482,22 +3482,20 @@ void V3d_View::ScreenCopy (const Handle(PlotMgt_PlotterDriver)& aPlotterDriver, #include //////////////////////////////////////////////////////////////// -Standard_Boolean V3d_View::Dump (const Standard_CString theFile, - const Image_TypeOfImage theBufferType) +Standard_Boolean V3d_View::Dump (const Standard_CString theFile, + const Graphic3d_BufferType& theBufferType) { Standard_Integer aWinWidth, aWinHeight; MyWindow->Size (aWinWidth, aWinHeight); - - Handle(Aspect_PixMap) aPixMap = ToPixMap (aWinWidth, aWinHeight, theBufferType); - return !aPixMap.IsNull() && aPixMap->Dump (theFile); + Image_AlienPixMap anImage; + return ToPixMap (anImage, aWinWidth, aWinHeight, theBufferType) && anImage.Save (theFile); } //////////////////////////////////////////////////////////////// -Standard_Boolean V3d_View::Dump (const Standard_CString theFile, +Standard_Boolean V3d_View::Dump (const Standard_CString theFile, const Aspect_FormatOfSheetPaper theFormat, - const Image_TypeOfImage theBufferType) + const Graphic3d_BufferType& theBufferType) { - Standard_Boolean isDone = Standard_False; // convert Aspect_FormatOfSheetPaper size to pixel ... Quantity_Length anSPWidth, anSPHeight; Aspect::ValuesOfFOSP (theFormat, anSPWidth, anSPHeight); @@ -3511,22 +3509,25 @@ Standard_Boolean V3d_View::Dump (const Standard_CString theFile, Quantity_Factor aScale = Min (anSPWidth / aWinWidth, anSPHeight / aWinHeight); aPixelWidth = Standard_Integer (aPixelWidth * aScale); aPixelHeight = Standard_Integer (aPixelHeight * aScale); + + Image_AlienPixMap anImage; + ToPixMap (anImage, aPixelWidth, aPixelHeight, theBufferType); + OSD_Environment anEnvGamma ("CSF_GAMMA_CORRECTION"); + TCollection_AsciiString strGamma (anEnvGamma.Value()); + if (!anImage.IsEmpty() && !strGamma.IsEmpty()) { - Handle(Aspect_PixMap) aBitmap = ToPixMap (aPixelWidth, aPixelHeight, theBufferType); - Standard_Real aGammaValue = 1.0; - OSD_Environment anEnvGamma ("CSF_GAMMA_CORRECTION"); - TCollection_AsciiString strGamma (anEnvGamma.Value()); - if (!strGamma.IsEmpty()) aGammaValue = strGamma.RealValue(); - isDone = !aBitmap.IsNull() && aBitmap->Dump (theFile, aGammaValue); + Standard_Real aGammaValue = strGamma.RealValue(); + anImage.AdjustGamma (aGammaValue); } - return isDone; + return anImage.Save (theFile); } //////////////////////////////////////////////////////////////// -Handle(Image_PixMap) V3d_View::ToPixMap (const Standard_Integer theWidth, - const Standard_Integer theHeight, - const Image_TypeOfImage theBufferType, - const Standard_Boolean theIsForceCentred) +Standard_Boolean V3d_View::ToPixMap (Image_PixMap& theImage, + const Standard_Integer theWidth, + const Standard_Integer theHeight, + const Graphic3d_BufferType& theBufferType, + const Standard_Boolean theIsForceCentred) { // always prefer hardware accelerated offscreen buffer Graphic3d_CView* cView = (Graphic3d_CView* )MyView->CView(); @@ -3575,7 +3576,7 @@ Handle(Image_PixMap) V3d_View::ToPixMap (const Standard_Integer theWidth, // but currently allow only dumping the window itself if (aFBOVPSizeX != aWinWidth || aFBOVPSizeY != aWinHeight) { - return Handle(Image_PixMap)(); + return Standard_False; } } @@ -3625,15 +3626,25 @@ Handle(Image_PixMap) V3d_View::ToPixMap (const Standard_Integer theWidth, MyViewMapping = prevMapping; MyView->SetViewMapping (prevMapping); + Standard_Boolean isSuccess = Standard_True; + // allocate image buffer for dumping - Image_CRawBufferData aRawBuffer; - Handle(Image_PixMap) anImageBitmap = new Image_PixMap (aFBOVPSizeX, aFBOVPSizeY, theBufferType); - anImageBitmap->AccessBuffer (aRawBuffer); - if (!MyView->BufferDump (aRawBuffer)) + if (theImage.IsEmpty() + || (Standard_Size )aFBOVPSizeX != theImage.SizeX() + || (Standard_Size )aFBOVPSizeY != theImage.SizeY()) { - // dump is failed! - anImageBitmap = Handle(Image_PixMap)(); + bool isBigEndian = Image_PixMap::IsBigEndianHost(); + Image_PixMap::ImgFormat aFormat = Image_PixMap::ImgUNKNOWN; + switch (theBufferType) + { + case Graphic3d_BT_RGB: aFormat = isBigEndian ? Image_PixMap::ImgRGB : Image_PixMap::ImgBGR; break; + case Graphic3d_BT_RGBA: aFormat = isBigEndian ? Image_PixMap::ImgRGBA : Image_PixMap::ImgBGRA; break; + case Graphic3d_BT_Depth: aFormat = Image_PixMap::ImgGrayF; break; + } + + isSuccess = isSuccess && theImage.InitZero (aFormat, aFBOVPSizeX, aFBOVPSizeY); } + isSuccess = isSuccess && MyView->BufferDump (theImage, theBufferType); // FBO now useless, free resources if (aFBOPtr != aPrevFBOPtr) @@ -3645,5 +3656,5 @@ Handle(Image_PixMap) V3d_View::ToPixMap (const Standard_Integer theWidth, MyView->FBOChangeViewport (aPrevFBOPtr, aPrevFBOVPSizeX, aPrevFBOVPSizeY); } cView->ptrFBO = aPrevFBOPtr; - return anImageBitmap; + return isSuccess; } diff --git a/src/ViewerTest/ViewerTest.cxx b/src/ViewerTest/ViewerTest.cxx index 148208c8cd..d017497813 100755 --- a/src/ViewerTest/ViewerTest.cxx +++ b/src/ViewerTest/ViewerTest.cxx @@ -54,7 +54,7 @@ #include #include #include -#include +#include #include #ifdef HAVE_CONFIG_H @@ -833,22 +833,21 @@ static Standard_Integer VDump (Draw_Interpretor& di, Standard_Integer argc, cons return 1; } - Image_TypeOfImage aBufferType = Image_TOI_RGB; - + Graphic3d_BufferType aBufferType = Graphic3d_BT_RGB; if (argc > 2) { TCollection_AsciiString aBuffTypeStr (argv[2]); if (TCollection_AsciiString::ISSIMILAR (aBuffTypeStr, TCollection_AsciiString ("rgb"))) { - aBufferType = Image_TOI_RGB; + aBufferType = Graphic3d_BT_RGB; } else if (TCollection_AsciiString::ISSIMILAR (aBuffTypeStr, TCollection_AsciiString ("rgba"))) { - aBufferType = Image_TOI_RGBA; + aBufferType = Graphic3d_BT_RGBA; } else if (TCollection_AsciiString::ISSIMILAR (aBuffTypeStr, TCollection_AsciiString ("depth"))) { - aBufferType = Image_TOI_FLOAT; + aBufferType = Graphic3d_BT_Depth; } } @@ -874,21 +873,20 @@ static Standard_Integer VDump (Draw_Interpretor& di, Standard_Integer argc, cons return 0; } - Handle(Image_PixMap) aPixMap = view->ToPixMap (aWidth, aHeight, aBufferType); - if (aPixMap.IsNull()) + Image_AlienPixMap aPixMap; + if (!view->ToPixMap (aPixMap, aWidth, aHeight, aBufferType)) { di << "Dumping failed!\n"; return 1; } - Image_CRawBufferData aRawBuffer; - aPixMap->AccessBuffer (aRawBuffer); - if (aRawBuffer.widthPx != aWidth || aRawBuffer.heightPx != aHeight) + if (aPixMap.SizeX() != Standard_Size(aWidth) + || aPixMap.SizeY() != Standard_Size(aHeight)) { - std::cout << "Warning! Dumped dimensions " << aRawBuffer.widthPx << "x" << aRawBuffer.heightPx - << " are lesser than requested " << aWidth << "x" << aHeight << "\n"; + std::cout << "Warning! Dumped dimensions " << aPixMap.SizeX() << "x" << aPixMap.SizeY() + << " are lesser than requested " << aWidth << "x" << aHeight << "\n"; } - if (!aPixMap->Dump (argv[1])) + if (!aPixMap.Save (argv[1])) { di << "Saving image failed!\n"; return 1; diff --git a/src/ViewerTest/ViewerTest_ViewerCommands.cxx b/src/ViewerTest/ViewerTest_ViewerCommands.cxx index d634c029ad..c7ac0b93d7 100755 --- a/src/ViewerTest/ViewerTest_ViewerCommands.cxx +++ b/src/ViewerTest/ViewerTest_ViewerCommands.cxx @@ -45,19 +45,21 @@ #include #include #include -#include +#include #include #include #include #include #include #include +#include #ifdef WNT #undef DrawText #endif #include +#include #ifndef WNT #include @@ -2151,10 +2153,8 @@ static int VPrintView (Draw_Interpretor& di, Standard_Integer argc, if (aMode != 0 && aMode != 1) aMode = 0; - Image_CRawBufferData aRawBuffer; - HDC anDC = CreateCompatibleDC(0); - // define compatible bitmap + HDC anDC = CreateCompatibleDC(0); BITMAPINFO aBitmapData; memset (&aBitmapData, 0, sizeof (BITMAPINFOHEADER)); aBitmapData.bmiHeader.biSize = sizeof (BITMAPINFOHEADER); @@ -2170,12 +2170,13 @@ static int VPrintView (Draw_Interpretor& di, Standard_Integer argc, aBitmapData.bmiHeader.biSizeImage = 0; // Create Device Independent Bitmap + void* aBitsOut = NULL; HBITMAP aMemoryBitmap = CreateDIBSection (anDC, &aBitmapData, DIB_RGB_COLORS, - &aRawBuffer.dataPtr, NULL, 0); + &aBitsOut, NULL, 0); HGDIOBJ anOldBitmap = SelectObject(anDC, aMemoryBitmap); Standard_Boolean isSaved = Standard_False, isPrinted = Standard_False; - if (aRawBuffer.dataPtr != 0) + if (aBitsOut != NULL) { if (aMode == 0) isPrinted = aView->Print(anDC,1,1,0,Aspect_PA_STRETCH); @@ -2185,11 +2186,13 @@ static int VPrintView (Draw_Interpretor& di, Standard_Integer argc, // succesfully printed into an intermediate buffer if (isPrinted) { - Handle(Image_PixMap) anImageBitmap = - new Image_PixMap ((Standard_PByte)aRawBuffer.dataPtr, - aWidth, aHeight, - aWidth*3 + aWidth%4, 24, 0); - isSaved = anImageBitmap->Dump(aFileName.ToCString()); + Image_PixMap aWrapper; + aWrapper.InitWrapper (Image_PixMap::ImgBGR, (Standard_Byte* )aBitsOut, aWidth, aHeight, aWidth * 3 + aWidth % 4); + aWrapper.SetTopDown (false); + + Image_AlienPixMap anImageBitmap; + anImageBitmap.InitCopy (aWrapper); + isSaved = anImageBitmap.Save (aFileName); } else { @@ -2898,7 +2901,9 @@ static int VReadPixel (Draw_Interpretor& theDI, return 1; } - Image_TypeOfImage aBufferType = Image_TOI_RGBA; + Image_PixMap::ImgFormat aFormat = Image_PixMap::IsBigEndianHost() ? Image_PixMap::ImgRGBA : Image_PixMap::ImgBGRA; + Graphic3d_BufferType aBufferType = Graphic3d_BT_RGBA; + Standard_Integer aWidth, aHeight; aView->Window()->Size (aWidth, aHeight); const Standard_Integer anX = atoi (theArgVec[1]); @@ -2916,28 +2921,34 @@ static int VReadPixel (Draw_Interpretor& theDI, TCollection_AsciiString aParam (theArgVec[anIter]); if (TCollection_AsciiString::ISSIMILAR (aParam, TCollection_AsciiString ("rgb"))) { - aBufferType = Image_TOI_RGB; + aFormat = Image_PixMap::IsBigEndianHost() ? Image_PixMap::ImgRGB : Image_PixMap::ImgBGR; + aBufferType = Graphic3d_BT_RGB; } else if (TCollection_AsciiString::ISSIMILAR (aParam, TCollection_AsciiString ("hls"))) { - aBufferType = Image_TOI_RGB; + aFormat = Image_PixMap::IsBigEndianHost() ? Image_PixMap::ImgRGB : Image_PixMap::ImgBGR; + aBufferType = Graphic3d_BT_RGB; toShowHls = Standard_True; } else if (TCollection_AsciiString::ISSIMILAR (aParam, TCollection_AsciiString ("rgbf"))) { - aBufferType = Image_TOI_RGBF; + aFormat = Image_PixMap::ImgRGBF; + aBufferType = Graphic3d_BT_RGB; } else if (TCollection_AsciiString::ISSIMILAR (aParam, TCollection_AsciiString ("rgba"))) { - aBufferType = Image_TOI_RGBA; + aFormat = Image_PixMap::IsBigEndianHost() ? Image_PixMap::ImgRGBA : Image_PixMap::ImgBGRA; + aBufferType = Graphic3d_BT_RGBA; } else if (TCollection_AsciiString::ISSIMILAR (aParam, TCollection_AsciiString ("rgbaf"))) { - aBufferType = Image_TOI_RGBAF; + aFormat = Image_PixMap::ImgRGBAF; + aBufferType = Graphic3d_BT_RGBA; } else if (TCollection_AsciiString::ISSIMILAR (aParam, TCollection_AsciiString ("depth"))) { - aBufferType = Image_TOI_FLOAT; + aFormat = Image_PixMap::ImgGrayF; + aBufferType = Graphic3d_BT_Depth; } else if (TCollection_AsciiString::ISSIMILAR (aParam, TCollection_AsciiString ("name"))) { @@ -2945,19 +2956,23 @@ static int VReadPixel (Draw_Interpretor& theDI, } } - Handle(Image_PixMap) anImage = aView->ToPixMap (aWidth, aHeight, aBufferType); - if (anImage.IsNull()) + Image_PixMap anImage; + if (!anImage.InitTrash (aFormat, aWidth, aHeight)) + { + std::cerr << "Image allocation failed\n"; + return 1; + } + else if (!aView->ToPixMap (anImage, aWidth, aHeight, aBufferType)) { std::cerr << "Image dump failed\n"; return 1; } Quantity_Parameter anAlpha; - Quantity_Color aColor = anImage->PixelColor (anX, anY, anAlpha); + Quantity_Color aColor = anImage.PixelColor (anX, anY, anAlpha); if (toShowName) { - if (aBufferType == Image_TOI_RGBA - || aBufferType == Image_TOI_RGBAF) + if (aBufferType == Graphic3d_BT_RGBA) { theDI << Quantity_Color::StringName (aColor.Name()) << " " << anAlpha << "\n"; } @@ -2971,8 +2986,7 @@ static int VReadPixel (Draw_Interpretor& theDI, switch (aBufferType) { default: - case Image_TOI_RGB: - case Image_TOI_RGBF: + case Graphic3d_BT_RGB: { if (toShowHls) { @@ -2984,13 +2998,12 @@ static int VReadPixel (Draw_Interpretor& theDI, } break; } - case Image_TOI_RGBA: - case Image_TOI_RGBAF: + case Graphic3d_BT_RGBA: { theDI << aColor.Red() << " " << aColor.Green() << " " << aColor.Blue() << " " << anAlpha << "\n"; break; } - case Image_TOI_FLOAT: + case Graphic3d_BT_Depth: { theDI << aColor.Red() << "\n"; break; @@ -3001,6 +3014,57 @@ static int VReadPixel (Draw_Interpretor& theDI, return 0; } +//============================================================================== +//function : VDiffImage +//purpose : The draw-command compares two images. +//============================================================================== + +static int VDiffImage (Draw_Interpretor& theDI, Standard_Integer theArgNb, const char** theArgVec) +{ + if (theArgNb < 6) + { + theDI << "Not enough arguments.\n"; + return 1; + } + + // image file names + const char* anImgPathRef = theArgVec[1]; + const char* anImgPathNew = theArgVec[2]; + + // get string tolerance and check its validity + Standard_Real aTolColor = atof (theArgVec[3]); + if (aTolColor < 0.0) + aTolColor = 0.0; + if (aTolColor > 1.0) + aTolColor = 1.0; + + Standard_Boolean toBlackWhite = (atoi (theArgVec[4]) == 1); + Standard_Boolean isBorderFilterOn = (atoi (theArgVec[5]) == 1); + + // image file of difference + const char* aDiffImagePath = (theArgNb >= 7) ? theArgVec[6] : NULL; + + // compare the images + Image_Diff aComparer; + if (!aComparer.Init (anImgPathRef, anImgPathNew, toBlackWhite)) + { + return 1; + } + + aComparer.SetColorTolerance (aTolColor); + aComparer.SetBorderFilterOn (isBorderFilterOn); + Standard_Integer aDiffColorsNb = aComparer.Compare(); + theDI << aDiffColorsNb << "\n"; + + // save image of difference + if (aDiffImagePath != NULL) + { + aComparer.SaveDiffImage (aDiffImagePath); + } + + return 0; +} + //======================================================================= //function : ViewerCommands //purpose : @@ -3131,4 +3195,7 @@ void ViewerTest::ViewerCommands(Draw_Interpretor& theCommands) "vreadpixel xPixel yPixel [{rgb|rgba|depth|hls|rgbf|rgbaf}=rgba] [name]" " : Read pixel value for active view", __FILE__, VReadPixel, group); + theCommands.Add("diffimage", + "diffimage : diffimage imageFile1 imageFile2 toleranceOfColor(0..1) blackWhite(1|0) borderFilter(1|0) [diffImageFile]", + __FILE__, VDiffImage, group); } diff --git a/src/Visual3d/Visual3d_View.cdl b/src/Visual3d/Visual3d_View.cdl index 0f6b6cb0fc..48e58647c5 100755 --- a/src/Visual3d/Visual3d_View.cdl +++ b/src/Visual3d/Visual3d_View.cdl @@ -87,8 +87,7 @@ uses ColorScale from Aspect, PrintAlgo from Aspect, - CRawBufferData from Image, - + BufferType from Graphic3d, CBitFields8 from Graphic3d, CView from Graphic3d, GraphicDriver from Graphic3d, @@ -121,7 +120,9 @@ uses FontAspect from OSD, AsciiString from TCollection, ExtendedString from TCollection, - CGraduatedTrihedron from Graphic3d + CGraduatedTrihedron from Graphic3d, + + PixMap from Image raises TransformError from Visual3d, @@ -1238,7 +1239,8 @@ is ---Purpose: Change offscreen FBO viewport. BufferDump( me : mutable; - buffer : in out CRawBufferData from Image ) + theImage : in out PixMap from Image; + theBufferType : BufferType from Graphic3d ) returns Boolean from Standard is static; ---Level: Public diff --git a/src/Visual3d/Visual3d_View.cxx b/src/Visual3d/Visual3d_View.cxx index 7e2c5e28d3..a53786b886 100755 --- a/src/Visual3d/Visual3d_View.cxx +++ b/src/Visual3d/Visual3d_View.cxx @@ -4277,9 +4277,10 @@ void Visual3d_View::FBOChangeViewport(Graphic3d_PtrFrameBuffer& theFBOPtr, theWidth, theHeight ); } -Standard_Boolean Visual3d_View::BufferDump (Image_CRawBufferData& theBuffer) +Standard_Boolean Visual3d_View::BufferDump (Image_PixMap& theImage, + const Graphic3d_BufferType& theBufferType) { - return MyGraphicDriver->BufferDump( MyCView, theBuffer); + return MyGraphicDriver->BufferDump (MyCView, theImage, theBufferType); } void Visual3d_View::EnableGLLight( const Standard_Boolean enable ) const diff --git a/src/WNT/WNT_ImageProcessor.cxx b/src/WNT/WNT_ImageProcessor.cxx index 119a7b0c38..662eca3387 100755 --- a/src/WNT/WNT_ImageProcessor.cxx +++ b/src/WNT/WNT_ImageProcessor.cxx @@ -43,7 +43,8 @@ #include #include #include -#include +#include +#include //***// #define I_SUCCESS Standard_True @@ -285,64 +286,45 @@ int __WNT_API SaveWindowToFile ( } // end SaveWindowToFile -int DumpBitmapToFile (Handle(WNT_GraphicDevice)& , HDC , - HBITMAP theHBitmap, - char* theFileName) +int DumpBitmapToFile (HBITMAP theHBitmap, + const char* theFileName) { - // Copy data from HBITMAP + // get informations about the bitmap BITMAP aBitmap; + if (GetObject (theHBitmap, sizeof(BITMAP), &aBitmap) == 0) + { + return I_ERROR; + } - // Get informations about the bitmap - GetObject (theHBitmap, sizeof(BITMAP), (LPSTR )&aBitmap); - Standard_Integer aWidth = aBitmap.bmWidth; - Standard_Integer aHeight = aBitmap.bmHeight; + Image_AlienPixMap anImage; + const Standard_Size aSizeRowBytes = Standard_Size(aBitmap.bmWidth) * 4; + if (!anImage.InitTrash (Image_PixMap::ImgBGR32, Standard_Size(aBitmap.bmWidth), Standard_Size(aBitmap.bmHeight), aSizeRowBytes)) + { + return I_ERROR; + } + anImage.SetTopDown (false); // Setup image data BITMAPINFOHEADER aBitmapInfo; memset (&aBitmapInfo, 0, sizeof(BITMAPINFOHEADER)); - aBitmapInfo.biSize = sizeof(BITMAPINFOHEADER); - aBitmapInfo.biWidth = aWidth; - aBitmapInfo.biHeight = aHeight; // positive means bottom-up! - aBitmapInfo.biPlanes = 1; - aBitmapInfo.biBitCount = 32; + aBitmapInfo.biSize = sizeof(BITMAPINFOHEADER); + aBitmapInfo.biWidth = aBitmap.bmWidth; + aBitmapInfo.biHeight = aBitmap.bmHeight; // positive means bottom-up! + aBitmapInfo.biPlanes = 1; + aBitmapInfo.biBitCount = 32; // use 32bit for automatic word-alignment per row aBitmapInfo.biCompression = BI_RGB; - Standard_Integer aBytesPerLine = aWidth * 4; - Standard_Byte* aDataPtr = new Standard_Byte[aBytesPerLine * aHeight]; - // Copy the pixels HDC aDC = GetDC (NULL); - Standard_Boolean isSuccess - = GetDIBits (aDC, // handle to DC - theHBitmap, // handle to bitmap - 0, // first scan line to set - aHeight, // number of scan lines to copy - aDataPtr, // array for bitmap bits - (LPBITMAPINFO )&aBitmapInfo, // bitmap data info - DIB_RGB_COLORS // RGB - ) != 0; - - if (isSuccess) - { - Handle(Image_PixMap) anImagePixMap = new Image_PixMap (aDataPtr, - aWidth, aHeight, - aBytesPerLine, - aBitmapInfo.biBitCount, - Standard_False); // bottom-up! - - // Release dump memory here - delete[] aDataPtr; + Standard_Boolean isSuccess = GetDIBits (aDC, theHBitmap, + 0, // first scan line to set + aBitmap.bmHeight, // number of scan lines to copy + anImage.ChangeData(), // array for bitmap bits + (LPBITMAPINFO )&aBitmapInfo, // bitmap data info + DIB_RGB_COLORS) != 0; - // save the image - anImagePixMap->Dump (theFileName); - } - else - { - // Release dump memory - delete[] aDataPtr; - } ReleaseDC (NULL, aDC); - return isSuccess ? I_SUCCESS : I_ERROR; + return (isSuccess && anImage.Save (theFileName)) ? I_SUCCESS : I_ERROR; } //***// @@ -401,8 +383,7 @@ int SaveBitmapToFile (Handle(WNT_GraphicDevice)& gDev, hNewBmp = hBmp; } - retVal = DumpBitmapToFile (gDev, NULL, - hNewBmp, fName); + retVal = DumpBitmapToFile (hNewBmp, fName); } // end __try __finally { if (hNewBmp != NULL && newBmp) DeleteObject (hNewBmp); diff --git a/src/WNT/WNT_PixMap.cdl b/src/WNT/WNT_PixMap.cdl index 32e7028e0e..ea8479880c 100755 --- a/src/WNT/WNT_PixMap.cdl +++ b/src/WNT/WNT_PixMap.cdl @@ -30,7 +30,7 @@ class PixMap from WNT ---Keywords: Bitmap, Pixmap inherits - PixMap from Aspect + Transient from Standard uses Handle from Aspect, @@ -99,7 +99,10 @@ is returns Integer from Standard is private; fields - myDC : Handle from Aspect is protected; - myBitmap : Handle from Aspect is protected; - myWND : Window from Aspect; + myDC : Handle from Aspect is protected; + myBitmap : Handle from Aspect is protected; + myWND : Window from Aspect; + myWidth : Integer from Standard is protected; + myHeight : Integer from Standard is protected; + myDepth : Integer from Standard is protected; end PixMap; diff --git a/src/WNT/WNT_PixMap.cxx b/src/WNT/WNT_PixMap.cxx index 78e887c097..8140d371a3 100755 --- a/src/WNT/WNT_PixMap.cxx +++ b/src/WNT/WNT_PixMap.cxx @@ -31,7 +31,7 @@ #include -extern int DumpBitmapToFile( Handle(WNT_GraphicDevice)&, HDC, HBITMAP, char* ); +extern int DumpBitmapToFile (HBITMAP, const char* ); #include @@ -50,15 +50,16 @@ Standard_Integer WNT_PixMap::PreferedDepth( } /////////////////////////////////////////////////////////////////////////////////////// -WNT_PixMap::WNT_PixMap ( const Handle(Aspect_Window)& aWindow, - const Standard_Integer aWidth, - const Standard_Integer anHeight, - const Standard_Integer aCDepth ) : -Aspect_PixMap(aWidth, anHeight, PreferedDepth(aWindow, aCDepth)) +WNT_PixMap::WNT_PixMap (const Handle(Aspect_Window)& theWindow, + const Standard_Integer theWidth, + const Standard_Integer theHeight, + const Standard_Integer theDepth) +: myWND (theWindow), + myWidth (theWidth), + myHeight (theHeight), + myDepth (PreferedDepth (theWindow, theDepth)) { - myWND = aWindow; - - const Handle(WNT_Window)& hWindow = Handle(WNT_Window)::DownCast(aWindow); + const Handle(WNT_Window)& hWindow = Handle(WNT_Window)::DownCast(theWindow); HDC hdc = GetDC ( (HWND)(hWindow->HWindow()) ); HDC hdcMem = CreateCompatibleDC ( hdc ); ReleaseDC ( (HWND)(hWindow->HWindow()), hdc ); @@ -80,8 +81,8 @@ Aspect_PixMap(aWidth, anHeight, PreferedDepth(aWindow, aCDepth)) ZeroMemory ( pBmi, sizeBmi ); pBmi->bmiHeader.biSize = sizeof (BITMAPINFOHEADER); //sizeBmi - pBmi->bmiHeader.biWidth = aWidth; - pBmi->bmiHeader.biHeight = anHeight; + pBmi->bmiHeader.biWidth = myWidth; + pBmi->bmiHeader.biHeight = myHeight; pBmi->bmiHeader.biPlanes = 1; pBmi->bmiHeader.biBitCount = myDepth; //WIL001: was 24 pBmi->bmiHeader.biCompression = BI_RGB; @@ -127,8 +128,8 @@ void WNT_PixMap::Destroy () } //////////////////////////////////////////////////////////// -Standard_Boolean WNT_PixMap::Dump ( const Standard_CString aFilename, - const Standard_Real aGammaValue ) const +Standard_Boolean WNT_PixMap::Dump (const Standard_CString theFilename, + const Standard_Real theGammaValue) const { // *** gamma correction must be implemented also on WNT system ... const Handle(WNT_Window) hWindow = Handle(WNT_Window)::DownCast(myWND); @@ -138,7 +139,7 @@ Standard_Boolean WNT_PixMap::Dump ( const Standard_CString aFilename, if ( dev.IsNull() ) return Standard_False; //Aspect_PixmapError::Raise ( "WNT_GraphicDevice is NULL" ); - return DumpBitmapToFile ( dev, (HDC)myDC, (HBITMAP)myBitmap, (Standard_PCharacter)aFilename ); + return DumpBitmapToFile ((HBITMAP)myBitmap, theFilename); } //////////////////////////////////////////////////////////// diff --git a/src/WNT/WNT_Window.cdl b/src/WNT/WNT_Window.cdl index 0a53f412d3..b1ae092110 100755 --- a/src/WNT/WNT_Window.cdl +++ b/src/WNT/WNT_Window.cdl @@ -47,7 +47,7 @@ class Window from WNT inherits Window from Aspect TypeOfResize from Aspect, FillMethod from Aspect, GradientFillMethod from Aspect, - PixMap from Aspect, + PixMap from Image, NameOfColor from Quantity, Color from Quantity, Parameter from Quantity, @@ -354,8 +354,8 @@ class Window from WNT inherits Window from Aspect -- or the area is out of the Window. raises WindowError from Aspect is virtual; - ToPixMap ( me ) - returns PixMap from Aspect + ToPixMap ( me ; theImage : in out PixMap from Image ) + returns Boolean ---Level : Public ---Purpose : dump the full contents of the window to a pixmap. is virtual; diff --git a/src/WNT/WNT_Window.cxx b/src/WNT/WNT_Window.cxx index 5da184dae2..134e1e6427 100755 --- a/src/WNT/WNT_Window.cxx +++ b/src/WNT/WNT_Window.cxx @@ -27,7 +27,7 @@ #include -#include +#include #include #include @@ -733,7 +733,16 @@ void WNT_Window :: RestoreArea ( Standard_Boolean WNT_Window::Dump (const Standard_CString theFilename, const Standard_Real theGammaValue) const { - return ToPixMap()->Dump (theFilename, theGammaValue); + Image_AlienPixMap anImg; + if (!ToPixMap (anImg) || anImg.IsEmpty()) + { + return Standard_False; + } + if (Abs (theGammaValue - 1.0) > 0.001) + { + anImg.AdjustGamma (theGammaValue); + } + return anImg.Save (theFilename); } // end WNT_Window :: Dump //***// //*************************** DumpArea ***********************************// @@ -753,61 +762,50 @@ Standard_Boolean WNT_Window::DumpArea (const Standard_CString theFilename, } // end WNT_Window :: DumpArea //***// -static Handle(Image_PixMap) ConvertBitmap (HBITMAP theHBitmap) +static Standard_Boolean ConvertBitmap (HBITMAP theHBitmap, + Image_PixMap& thePixMap) { - Handle(Image_PixMap) anImagePixMap; - // Copy data from HBITMAP + // Get informations about the bitmap BITMAP aBitmap; + if (GetObject (theHBitmap, sizeof(BITMAP), (LPSTR )&aBitmap) == 0) + { + return Standard_False; + } - // Get informations about the bitmap - GetObject (theHBitmap, sizeof(BITMAP), (LPSTR )&aBitmap); - Standard_Integer aWidth = aBitmap.bmWidth; - Standard_Integer aHeight = aBitmap.bmHeight; + const Standard_Size aSizeRowBytes = Standard_Size(aBitmap.bmWidth) * 4; + if (!thePixMap.InitTrash (Image_PixMap::ImgBGR32, Standard_Size(aBitmap.bmWidth), Standard_Size(aBitmap.bmHeight), aSizeRowBytes)) + { + return Standard_False; + } + thePixMap.SetTopDown (false); // Setup image data BITMAPINFOHEADER aBitmapInfo; memset (&aBitmapInfo, 0, sizeof(BITMAPINFOHEADER)); - aBitmapInfo.biSize = sizeof(BITMAPINFOHEADER); - aBitmapInfo.biWidth = aWidth; - aBitmapInfo.biHeight = aHeight; // positive means bottom-up! - aBitmapInfo.biPlanes = 1; - aBitmapInfo.biBitCount = 32; + aBitmapInfo.biSize = sizeof(BITMAPINFOHEADER); + aBitmapInfo.biWidth = aBitmap.bmWidth; + aBitmapInfo.biHeight = aBitmap.bmHeight; // positive means bottom-up! + aBitmapInfo.biPlanes = 1; + aBitmapInfo.biBitCount = 32; // use 32bit for automatic word-alignment per row aBitmapInfo.biCompression = BI_RGB; - Standard_Integer aBytesPerLine = aWidth * 4; - Standard_Byte* aDataPtr = new Standard_Byte[aBytesPerLine * aHeight]; - // Copy the pixels HDC aDC = GetDC (NULL); - Standard_Boolean isSuccess - = GetDIBits (aDC, // handle to DC - theHBitmap, // handle to bitmap - 0, // first scan line to set - aHeight, // number of scan lines to copy - aDataPtr, // array for bitmap bits - (LPBITMAPINFO )&aBitmapInfo, // bitmap data info - DIB_RGB_COLORS // RGB - ) != 0; - - if (isSuccess) - { - anImagePixMap = new Image_PixMap (aDataPtr, - aWidth, aHeight, - aBytesPerLine, - aBitmapInfo.biBitCount, - Standard_False); // bottom-up! - } - // Release dump memory - delete[] aDataPtr; + Standard_Boolean isSuccess = GetDIBits (aDC, theHBitmap, + 0, // first scan line to set + aBitmap.bmHeight, // number of scan lines to copy + thePixMap.ChangeData(), // array for bitmap bits + (LPBITMAPINFO )&aBitmapInfo, // bitmap data info + DIB_RGB_COLORS) != 0; ReleaseDC (NULL, aDC); - return anImagePixMap; + return isSuccess; } -Handle(Aspect_PixMap) WNT_Window::ToPixMap() const +Standard_Boolean WNT_Window::ToPixMap (Image_PixMap& thePixMap) const { if (myDoubleBuffer && myHPixmap) { - return ConvertBitmap ((HBITMAP )myHPixmap); + return ConvertBitmap ((HBITMAP )myHPixmap, thePixMap); } RECT aRect; @@ -825,13 +823,13 @@ Handle(Aspect_PixMap) WNT_Window::ToPixMap() const HBITMAP anHBitmapOld = (HBITMAP )SelectObject (aMemDC, anHBitmapDump); BitBlt (aMemDC, 0, 0, aWidth, aHeight, aSrcDC, 0, 0, SRCCOPY); - Handle(Image_PixMap) anImagePixMap = ConvertBitmap (anHBitmapDump); + Standard_Boolean isSuccess = ConvertBitmap (anHBitmapDump, thePixMap); // Free objects DeleteObject (SelectObject (aMemDC, anHBitmapOld)); DeleteDC (aMemDC); - return anImagePixMap; + return isSuccess; } //****************************** Load ************************************// diff --git a/src/Xw/Xw_PixMap.cdl b/src/Xw/Xw_PixMap.cdl index e76abb64b4..799339a9ef 100755 --- a/src/Xw/Xw_PixMap.cdl +++ b/src/Xw/Xw_PixMap.cdl @@ -30,7 +30,7 @@ class PixMap from Xw ---Keywords: Bitmap, Pixmap, X11 inherits - PixMap from Aspect + Transient from Standard uses Handle from Aspect, Color from Quantity, @@ -97,4 +97,7 @@ is fields myPixmap : Handle from Aspect is protected; myWindow : Window from Xw; + myWidth : Integer from Standard is protected; + myHeight : Integer from Standard is protected; + myDepth : Integer from Standard is protected; end PixMap; diff --git a/src/Xw/Xw_PixMap.cxx b/src/Xw/Xw_PixMap.cxx index e9035cf899..7512f42364 100755 --- a/src/Xw/Xw_PixMap.cxx +++ b/src/Xw/Xw_PixMap.cxx @@ -28,6 +28,9 @@ #define xTRACE 1 +#include +#include + #include #include @@ -36,9 +39,6 @@ #include #include -#include -#include - XW_STATUS Xw_save_xwd_image ( void*, void*, char* ); XW_STATUS Xw_save_bmp_image ( void*, void*, char* ); XW_STATUS Xw_save_gif_image ( void*, void*, char* ); @@ -63,15 +63,15 @@ Standard_Integer Xw_PixMap::PreferedDepth( ////////////////////////////////////////////////////////////////////////////////////////// -Xw_PixMap::Xw_PixMap ( const Handle(Aspect_Window)& aWindow, - const Standard_Integer aWidth, - const Standard_Integer anHeight, - const Standard_Integer aDepth ) : - Aspect_PixMap(aWidth, anHeight, PreferedDepth(aWindow, aDepth)) +Xw_PixMap::Xw_PixMap (const Handle(Aspect_Window)& theWindow, + const Standard_Integer theWidth, + const Standard_Integer theHeight, + const Standard_Integer theDepth) +: myWindow (Handle(Xw_Window)::DownCast(theWindow)), + myWidth (theWidth), + myHeight (theHeight), + myDepth (PreferedDepth (theWindow, theDepth)) { - - myWindow = Handle(Xw_Window)::DownCast(aWindow); - XW_EXT_WINDOW *pwindow = (XW_EXT_WINDOW*) myWindow->ExtendedWindow(); Xw_print_error(); @@ -99,46 +99,54 @@ Xw_PixMap::Destroy () } } - //////////////////////////////////////////////////////////// -Standard_Boolean Xw_PixMap::Dump (const Standard_CString theFilename, - const Standard_Real theGammaValue) const +Standard_Boolean Xw_PixMap::Dump (const Standard_CString theFileName, + const Standard_Real theGammaValue) const { // the attributes XWindowAttributes winAttr; XW_EXT_WINDOW *pwindow = (XW_EXT_WINDOW*) myWindow->ExtendedWindow(); XGetWindowAttributes (_DISPLAY, _WINDOW, &winAttr); - - // find the image - XImage* pximage = XGetImage (_DISPLAY, myPixmap, - 0, 0, myWidth, myHeight, - AllPlanes, ZPixmap); - if (pximage == NULL) + if (winAttr.visual->c_class != TrueColor) { + std::cerr << "Visual Type not supported!"; return Standard_False; } - if (winAttr.visual->c_class == TrueColor) + Image_AlienPixMap anImage; + bool isBigEndian = Image_PixMap::IsBigEndianHost(); + const Standard_Size aSizeRowBytes = Standard_Size(winAttr.width) * 4; + if (!anImage.InitTrash (isBigEndian ? Image_PixMap::ImgRGB32 : Image_PixMap::ImgBGR32, + Standard_Size(winAttr.width), Standard_Size(winAttr.height), aSizeRowBytes)) { - Standard_Byte* aDataPtr = (Standard_Byte* )pximage->data; - Handle(Image_PixMap) anImagePixMap = new Image_PixMap (aDataPtr, - pximage->width, pximage->height, - pximage->bytes_per_line, - pximage->bits_per_pixel, - Standard_True); - // destroy the image - XDestroyImage (pximage); - - // save the image - return anImagePixMap->Dump (theFilename, theGammaValue); + return Standard_False; } - else + anImage.SetTopDown (true); + + XImage* anXImage = XCreateImage (_DISPLAY, winAttr.visual, + 32, ZPixmap, 0, (char* )anImage.ChangeData(), winAttr.width, winAttr.height, 32, int(aSizeRowBytes)); + anXImage->bitmap_bit_order = anXImage->byte_order = (isBigEndian ? MSBFirst : LSBFirst); + if (XGetSubImage (_DISPLAY, myPixmap, + 0, 0, winAttr.width, winAttr.height, + AllPlanes, ZPixmap, anXImage, 0, 0) == NULL) { - std::cerr << "Visual Type not supported!"; - // destroy the image - XDestroyImage (pximage); + anXImage->data = NULL; + XDestroyImage (anXImage); return Standard_False; } + + // destroy the image + anXImage->data = NULL; + XDestroyImage (anXImage); + + // save the image + if (Abs (theGammaValue - 1.0) > 0.001) + { + anImage.AdjustGamma (theGammaValue); + } + + // save the image + return anImage.Save (theFileName); } //////////////////////////////////////////////////////////// diff --git a/src/Xw/Xw_Window.cdl b/src/Xw/Xw_Window.cdl index b5ce738f87..282bdedf48 100755 --- a/src/Xw/Xw_Window.cdl +++ b/src/Xw/Xw_Window.cdl @@ -49,7 +49,7 @@ uses Handle from Aspect, FillMethod from Aspect, GradientFillMethod from Aspect, - PixMap from Aspect, + PixMap from Image, NameOfColor from Quantity, Parameter from Quantity, Ratio from Quantity, @@ -330,8 +330,8 @@ is -- or the area is out of the Window. raises WindowError from Aspect is virtual; - ToPixMap ( me ) - returns PixMap from Aspect + ToPixMap ( me ; theImage : in out PixMap from Image ) + returns Boolean ---Level : Public ---Purpose : dump the full contents of the window to a pixmap. is virtual; diff --git a/src/Xw/Xw_Window.cxx b/src/Xw/Xw_Window.cxx index 584c24b38d..a1065ba858 100755 --- a/src/Xw/Xw_Window.cxx +++ b/src/Xw/Xw_Window.cxx @@ -77,7 +77,7 @@ #include //} #include -#include +#include #include @@ -862,15 +862,14 @@ Standard_Boolean Xw_Window::DumpArea (const Standard_CString theFilename, return Standard_Boolean(aStatus); } -Handle(Aspect_PixMap) Xw_Window::ToPixMap() const +Standard_Boolean Xw_Window::ToPixMap (Image_PixMap& thePixMap) const { - Handle(Image_PixMap) anImagePixMap; int aDummy, aWidth, aHeight; XW_WINDOWSTATE state = Xw_get_window_position (MyExtendedWindow, &aDummy, &aDummy, &aWidth, &aHeight); if (state == XW_WS_UNKNOWN) { - return anImagePixMap; + return Standard_False; } XW_EXT_IMAGEDATA* pimage = NULL; @@ -895,22 +894,27 @@ Handle(Aspect_PixMap) Xw_Window::ToPixMap() const if (pimage == NULL) { - return anImagePixMap; + return Standard_False; } XImage* pximage = (pimage->zximage) ? pimage->zximage : pimage->pximage; XW_EXT_WINDOW* pwindow = (XW_EXT_WINDOW* )MyExtendedWindow; - if (pwindow->pcolormap->visual->c_class == TrueColor) + if (pwindow->pcolormap->visual->c_class != TrueColor) { - Standard_Byte* aDataPtr = (Standard_Byte* )pximage->data; - anImagePixMap = new Image_PixMap (aDataPtr, - pximage->width, pximage->height, - pximage->bytes_per_line, - pximage->bits_per_pixel, - Standard_True); + return Standard_False; } + + const bool isBigEndian = (pximage->byte_order == MSBFirst); + Image_PixMap::ImgFormat aFormat = (pximage->bits_per_pixel == 32) + ? (isBigEndian ? Image_PixMap::ImgRGB32 : Image_PixMap::ImgBGR32) + : (isBigEndian ? Image_PixMap::ImgRGB : Image_PixMap::ImgBGR); + Image_PixMap aWrapper; + aWrapper.InitWrapper (aFormat, (Standard_Byte* )pximage->data, pximage->width, pximage->height, pximage->bytes_per_line); + aWrapper.SetTopDown (true); + + Standard_Boolean isSuccess = thePixMap.InitCopy (aWrapper); Xw_close_image (pimage); - return anImagePixMap; + return isSuccess; } Standard_Boolean Xw_Window::Load (const Standard_CString aFilename) const { diff --git a/src/Xw/Xw_save_image.cxx b/src/Xw/Xw_save_image.cxx index a317e10cb3..f759c3c166 100755 --- a/src/Xw/Xw_save_image.cxx +++ b/src/Xw/Xw_save_image.cxx @@ -34,13 +34,14 @@ # include #endif +#include +#include + #include #ifdef HAVE_STRINGS_H # include #endif -#include - #ifdef XW_PROTOTYPE XW_STATUS Xw_save_image_adv (Display *aDisplay,Window aWindow,XWindowAttributes aWinAttr,XImage *aPximage,Colormap aColormap,int aNcolors,char *filename) #else @@ -54,22 +55,22 @@ int ncolors; char *filename; #endif /*XW_PROTOTYPE*/ { - if (aWinAttr.visual->c_class == TrueColor) - { - Standard_Byte* aDataPtr = (Standard_Byte* )aPximage->data; - Handle(Image_PixMap) anImagePixMap = new Image_PixMap (aDataPtr, - aPximage->width, aPximage->height, - aPximage->bytes_per_line, - aPximage->bits_per_pixel, - Standard_True); - // save the image - return anImagePixMap->Dump (filename) ? XW_SUCCESS : XW_ERROR; - } - else + if (aWinAttr.visual->c_class != TrueColor) { std::cerr << "Visual Type not supported!"; - return XW_SUCCESS; + return XW_ERROR; } + + const bool isBigEndian = (aPximage->byte_order == MSBFirst); + Image_PixMap::ImgFormat aFormat = (aPximage->bits_per_pixel == 32) + ? (isBigEndian ? Image_PixMap::ImgRGB32 : Image_PixMap::ImgBGR32) + : (isBigEndian ? Image_PixMap::ImgRGB : Image_PixMap::ImgBGR); + Image_PixMap aWrapper; + aWrapper.InitWrapper (aFormat, (Standard_Byte* )aPximage->data, aPximage->width, aPximage->height, aPximage->bytes_per_line); + aWrapper.SetTopDown (true); + + Image_AlienPixMap anAlienImage; + return (anAlienImage.InitCopy (aWrapper) && anAlienImage.Save (filename)) ? XW_SUCCESS : XW_ERROR; } #ifdef XW_PROTOTYPE -- 2.20.1