#include #include #include #include #include #ifdef TRACE static int Verbose = 0 ; #endif Image_Convertor::Image_Convertor() { myDitheringMethod = Image_DM_NearestColor;} void Image_Convertor::SetDitheringMethod( const Image_DitheringMethod Method ) { myDitheringMethod = Method ; } Handle(Image_PseudoColorImage) Image_Convertor::Convert( const Handle(Image_ColorImage)& aImage, const Handle(Aspect_ColorMap)& aColorMap ) const { Handle(Image_PseudoColorImage) ret_image = NULL ; if ( myDitheringMethod == Image_DM_NearestColor ) { ret_image = NearestDithering( aImage, aColorMap ) ; } else if ( myDitheringMethod == Image_DM_ErrorDiffusion ) { ret_image = ErrorDiffusionDithering( aImage, aColorMap ) ; } return ret_image ; } Handle(Image_PseudoColorImage) Image_Convertor::Convert( const Handle(Image_PseudoColorImage)& aImage, const Handle(Aspect_ColorMap)& aColorMap ) const { Handle(Image_PseudoColorImage) ret_image = NULL ; if ( myDitheringMethod == Image_DM_NearestColor ) { ret_image = NearestDithering( aImage, aColorMap ) ; } else if ( myDitheringMethod == Image_DM_ErrorDiffusion ) { ret_image = ErrorDiffusionDithering( aImage, aColorMap ) ; } return ret_image ; } Handle(Image_ColorImage) Image_Convertor::Convert( const Handle(Image_PseudoColorImage)& aImage ) const { Handle(Image_ColorImage) ret_image = NULL ; Standard_Integer x, y, val, lastval ; Quantity_Color aColor ; Standard_Integer UpX = aImage->UpperX() ; Standard_Integer UpY = aImage->UpperY() ; ret_image = new Image_ColorImage( aImage->LowerX(), aImage->LowerY(), aImage->Width() , aImage->Height() ) ; lastval = aImage->Pixel(aImage->LowerX(), aImage->LowerY() ).Value() ; aColor = aImage->ColorMap()->FindEntry(lastval).Color() ; for ( y = aImage->LowerY() ; y <= UpY ; y++ ) { for ( x = aImage->LowerX() ; x <= UpX ; x++ ) { val = aImage->Pixel(x,y).Value() ; if ( lastval != val ) { lastval = val ; aColor = aImage->ColorMap()->FindEntry(lastval).Color() ; } ret_image->SetPixel( x, y, aColor ); } } return( ret_image ) ; } Handle(Image_PseudoColorImage) Image_Convertor::NearestDithering( const Handle(Image_ColorImage)& aImage, const Handle(Aspect_ColorMap)& aColorMap ) const { Handle(Image_PseudoColorImage) ret_image = NULL ; Standard_Integer x, y, index ; Quantity_Color lastval, val ; Standard_Integer UpX = aImage->UpperX() ; Standard_Integer UpY = aImage->UpperY() ; ret_image = new Image_PseudoColorImage( aImage->LowerX(), aImage->LowerY(), aImage->Width() , aImage->Height(), aColorMap ); lastval = aImage->PixelColor(aImage->LowerX(),aImage->LowerY()) ; index = aColorMap->NearestEntry( lastval ).Index() ; for ( y = aImage->LowerY() ; y <= UpY ; y++ ) { for ( x = aImage->LowerX() ; x <= UpX ; x++ ) { val = aImage->PixelColor(x,y) ; if ( !( val == lastval ) ) { lastval = val ; index = aColorMap->NearestEntry( lastval ).Index() ; } ret_image->SetPixel( x, y, index ) ; } } return( ret_image ) ; } Handle(Image_PseudoColorImage) Image_Convertor::NearestDithering( const Handle(Image_PseudoColorImage)& aImage, const Handle(Aspect_ColorMap)& aColorMap ) const { Handle(Image_PseudoColorImage) ret_image = NULL ; Standard_Integer x,y, val, lastval, index ; Standard_Integer UpX = aImage->UpperX() ; Standard_Integer UpY = aImage->UpperY() ; Image_LookupTable ColorMapLookup ; Aspect_ColorMapEntry aEntry ; Standard_Integer i, size ; for ( i = 1 , size = aImage->ColorMap()->Size() ; i <= size ; i++ ) { aEntry = aImage->ColorMap()->Entry(i) ; index = aColorMap->NearestEntry( aEntry.Color() ).Index() ; ColorMapLookup.Bind( aEntry.Index(), index ) ; } ret_image = new Image_PseudoColorImage( aImage->LowerX(), aImage->LowerY(), aImage->Width() , aImage->Height(), aColorMap ); lastval = aImage->Pixel( aImage->LowerX(), aImage->LowerY() ).Value() ; index = ColorMapLookup.Find( lastval ).Value() ; for ( y = aImage->LowerY() ; y <= UpY ; y++ ) { for ( x = aImage->LowerX() ; x <= UpX ; x++ ) { val = aImage->Pixel(x,y).Value() ; if ( val != lastval ) { lastval = val ; index = ColorMapLookup.Find( lastval ).Value() ; } ret_image->SetPixel( x, y, index ) ; } } return( ret_image ) ; } static Standard_Boolean ManageLastKernelError = 1 ; static struct { Standard_Real v ; Standard_Integer dx, dy ; } Kernel[4] = { { 7./16., 1, 0 }, { 3./16., -1, 1 }, { 5./16., 0, 1 }, { 1./16., 1, 1 } } ; Handle(Image_PseudoColorImage) Image_Convertor::ErrorDiffusionDithering( const Handle(Image_PseudoColorImage)& RefImage, const Handle(Aspect_ColorMap)& aColorMap ) const { Handle(Image_PseudoColorImage) ret_image = NULL ; Standard_Integer UpX = RefImage->UpperX() ; Standard_Integer UpY = RefImage->UpperY() ; Standard_Integer LowX = RefImage->LowerX() ; Standard_Integer LowY = RefImage->LowerY() ; Standard_Integer x,y, index, i, nx,ny ; Standard_Integer val, lastval ; Standard_Integer Error, ErrorDiff, pix, npix, MinIndex, MaxIndex ; Aspect_IndexPixel aPixel ; Image_LookupTable ColorMapLookup ; Aspect_ColorMapEntry aEntry ; Standard_Integer size ; MaxIndex = MinIndex = RefImage->ColorMap()->Entry(1).Index() ; for ( i = 1 , size = RefImage->ColorMap()->Size() ; i <= size ; i++ ) { aEntry = RefImage->ColorMap()->Entry(i) ; MinIndex = Min( aEntry.Index(), MinIndex ) ; MaxIndex = Max( aEntry.Index(), MaxIndex ) ; index = aColorMap->NearestEntry( aEntry.Color() ).Index() ; ColorMapLookup.Bind( aEntry.Index(), index ) ; } Handle(Image_PseudoColorImage) aImage = Handle(Image_PseudoColorImage)::DownCast( RefImage->Dup() ) ; ret_image = new Image_PseudoColorImage( aImage->LowerX(), aImage->LowerY(), aImage->Width() , aImage->Height(), aColorMap ); lastval = aImage->Pixel( aImage->LowerX(), aImage->LowerY() ).Value() ; index = ColorMapLookup.Find( lastval ).Value() ; for ( y = aImage->LowerY() ; y <= UpY ; y++ ) { for ( x = aImage->LowerX() ; x <= UpX ; x++ ) { val = aImage->Pixel(x,y).Value() ; if ( ! ( val == lastval ) ) { lastval = val ; index = ColorMapLookup.Find( lastval ).Value() ; } ErrorDiff = Error = val - index ; #ifdef TRACE if ( Verbose > 3 ) cout << "ErrorDiffusion : " << Error << endl << flush ; #endif if ( Error != 0 ) { for ( i = 0 ; i < 4 ; i++ ) { nx = x+Kernel[i].dx ; ny = y+Kernel[i].dy ; if ( nx >= LowX && nx <= UpX && ny >= LowY && ny <= UpY ) { aImage->Pixel( nx, ny, aPixel ) ; pix = aPixel.Value() ; if ( ManageLastKernelError && i == 3 ) { // Last one npix = pix + ErrorDiff ; } else { npix = pix + Standard_Integer( Kernel[i].v * Error ) ; } // ErrorDiffusion may produce Pixel out of ColorMap // Clamp value to min max of ColorMap npix = Max( npix, MinIndex ) ; npix = Min( npix, MaxIndex ) ; ErrorDiff -= ( npix - pix ) ; #ifdef TRACE if ( Verbose > 2 && i == 3 ) { cout << "ErrorDiffusion Last Error: " << (ErrorDiff-( Kernel[i].v*Error)) <SetPixel( nx, ny, aPixel ) ; } } } ret_image->SetPixel( x, y, index ) ; } } return( ret_image ) ; } Handle(Image_PseudoColorImage) Image_Convertor::ErrorDiffusionDithering( const Handle(Image_ColorImage)& RefImage, const Handle(Aspect_ColorMap)& aColorMap ) const { Handle(Image_PseudoColorImage) ret_image = NULL ; Standard_Integer UpX = RefImage->UpperX() ; Standard_Integer UpY = RefImage->UpperY() ; Standard_Integer LowX = RefImage->LowerX() ; Standard_Integer LowY = RefImage->LowerY() ; Standard_Integer x,y, index, i, nx,ny ; Quantity_Color val, lastval, NewCol ; Aspect_ColorMapEntry aEntry ; Aspect_ColorPixel aPixel ; Standard_Real RedError, GreenError, BlueError, r,g,b,cr,cg,cb ; Standard_Real RedDiffError, GreenDiffError, BlueDiffError ; Handle(Image_ColorImage) aImage = Handle(Image_ColorImage)::DownCast( RefImage->Dup() ) ; ret_image = new Image_PseudoColorImage( aImage->LowerX(), aImage->LowerY(), aImage->Width() , aImage->Height(), aColorMap ); lastval = aImage->PixelColor( aImage->LowerX(), aImage->LowerY() ) ; aEntry = aColorMap->NearestEntry( lastval ) ; index = aEntry.Index() ; for ( y = aImage->LowerY() ; y <= UpY ; y++ ) { for ( x = aImage->LowerX() ; x <= UpX ; x++ ) { val = aImage->PixelColor(x,y) ; if ( ! ( val == lastval ) ) { lastval = val ; aEntry = aColorMap->NearestEntry( lastval ) ; index = aEntry.Index() ; } RedDiffError = RedError = val.Red() - aEntry.Color().Red() ; GreenDiffError = GreenError = val.Green() - aEntry.Color().Green() ; BlueDiffError = BlueError = val.Blue() - aEntry.Color().Blue() ; #ifdef TRACE if ( Verbose > 3 ) cout << "ErrorDiffusion : " << RedError << "," << GreenError << "," << BlueError << "," << endl << flush ; #endif if ( RedError != 0. && GreenError != 0. && BlueError != 0. ) { for ( i = 0 ; i < 4 ; i++ ) { nx = x+Kernel[i].dx ; ny = y+Kernel[i].dy ; if ( nx >= LowX && nx <= UpX && ny >= LowY && ny <= UpY ) { aImage->Pixel( nx, ny, aPixel ) ; aPixel.Value().Values( r,g,b, Quantity_TOC_RGB ) ; if ( ManageLastKernelError && i == 3 ) { // Last one cr = r + RedDiffError ; cg = g + GreenDiffError ; cb = b + BlueDiffError ; } else { cr = r + ( Kernel[i].v * RedError ) ; cg = g + ( Kernel[i].v * GreenError ) ; cb = b + ( Kernel[i].v * BlueError ) ; } // ErrorDiffusion may produce Pixel out of ColorMap // Clamp Color cr = Max( cr, 0. ) ; cr = Min( cr, 1. ) ; cg = Max( cg, 0. ) ; cg = Min( cg, 1. ) ; cb = Max( cb, 0. ) ; cb = Min( cb, 1. ) ; RedDiffError -= ( cr - r ) ; GreenDiffError -= ( cg - g ) ; BlueDiffError -= ( cb - b ) ; #ifdef TRACE if ( Verbose > 2 && i == 3 ) { cout << "ErrorDiffusion Last Error: " << RedDiffError << "," << GreenDiffError << "," << BlueDiffError << "," << endl << flush ; } #endif NewCol.SetValues( cr,cg,cb, Quantity_TOC_RGB ) ; aPixel.SetValue( NewCol ) ; aImage->SetPixel( nx, ny, aPixel ) ; } } } ret_image->SetPixel( x, y, index ) ; } } return( ret_image ) ; }