1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
22 #include <rtl/alloc.h>
23 #include <vcl/bitmapaccess.hxx>
26 #include "impoctree.hxx"
28 static const sal_uInt8 pImplMask
[8] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };
30 ImpNodeCache::ImpNodeCache( const sal_uLong nInitSize
) :
33 const sal_uLong nSize
= nInitSize
+ 4;
35 for( sal_uLong i
= 0; i
< nSize
; i
++ )
37 OctreeNode
* pNewNode
= new NODE
;
39 pNewNode
->pNextInCache
= pActNode
;
44 ImpNodeCache::~ImpNodeCache()
48 OctreeNode
* pNode
= pActNode
;
50 pActNode
= pNode
->pNextInCache
;
55 Octree::Octree(const BitmapReadAccess
& rReadAcc
, sal_uLong nColors
)
64 pNodeCache
= new ImpNodeCache( nColors
);
65 memset( pReduce
, 0, ( OCTREE_BITS
+ 1 ) * sizeof( NODE
* ) );
69 const long nWidth
= pAcc
->Width();
70 const long nHeight
= pAcc
->Height();
72 if( pAcc
->HasPalette() )
74 for( long nY
= 0; nY
< nHeight
; nY
++ )
76 for( long nX
= 0; nX
< nWidth
; nX
++ )
78 pColor
= &(BitmapColor
&) pAcc
->GetPaletteColor( pAcc
->GetPixelIndex( nY
, nX
) );
82 while( nLeafCount
> nMax
)
93 for( long nY
= 0; nY
< nHeight
; nY
++ )
95 for( long nX
= 0; nX
< nWidth
; nX
++ )
97 aColor
= pAcc
->GetPixel( nY
, nX
);
101 while( nLeafCount
> nMax
)
111 ImplDeleteOctree( &pTree
);
115 void Octree::ImplDeleteOctree( NODE
** ppNode
)
117 for (OctreeNode
* i
: (*ppNode
)->pChild
)
120 ImplDeleteOctree( &i
);
123 pNodeCache
->ImplReleaseNode( *ppNode
);
127 void Octree::ImplAdd( NODE
** ppNode
)
129 // possibly generate new nodes
132 *ppNode
= pNodeCache
->ImplGetFreeNode();
133 (*ppNode
)->bLeaf
= ( OCTREE_BITS
== nLevel
);
135 if( (*ppNode
)->bLeaf
)
139 (*ppNode
)->pNext
= pReduce
[ nLevel
];
140 pReduce
[ nLevel
] = *ppNode
;
144 if( (*ppNode
)->bLeaf
)
147 (*ppNode
)->nRed
+= pColor
->GetRed();
148 (*ppNode
)->nGreen
+= pColor
->GetGreen();
149 (*ppNode
)->nBlue
+= pColor
->GetBlue();
153 const sal_uLong nShift
= 7 - nLevel
;
154 const sal_uInt8 cMask
= pImplMask
[ nLevel
];
155 const sal_uLong nIndex
= ( ( ( pColor
->GetRed() & cMask
) >> nShift
) << 2 ) |
156 ( ( ( pColor
->GetGreen() & cMask
) >> nShift
) << 1 ) |
157 ( ( pColor
->GetBlue() & cMask
) >> nShift
);
160 ImplAdd( &(*ppNode
)->pChild
[ nIndex
] );
164 void Octree::ImplReduce()
168 sal_uLong nRedSum
= 0;
169 sal_uLong nGreenSum
= 0;
170 sal_uLong nBlueSum
= 0;
171 sal_uLong nChildren
= 0;
173 for ( i
= OCTREE_BITS
- 1; i
&& !pReduce
[i
]; i
-- ) {}
175 pNode
= pReduce
[ i
];
176 pReduce
[ i
] = pNode
->pNext
;
178 for ( i
= 0; i
< 8; i
++ )
180 if ( pNode
->pChild
[ i
] )
182 NODE
* pChild
= pNode
->pChild
[ i
];
184 nRedSum
+= pChild
->nRed
;
185 nGreenSum
+= pChild
->nGreen
;
186 nBlueSum
+= pChild
->nBlue
;
187 pNode
->nCount
+= pChild
->nCount
;
189 pNodeCache
->ImplReleaseNode( pNode
->pChild
[ i
] );
190 pNode
->pChild
[ i
] = nullptr;
196 pNode
->nRed
= nRedSum
;
197 pNode
->nGreen
= nGreenSum
;
198 pNode
->nBlue
= nBlueSum
;
199 nLeafCount
-= --nChildren
;
202 void Octree::CreatePalette( NODE
* pNode
)
206 pNode
->nPalIndex
= nPalIndex
;
207 aPal
[ nPalIndex
++ ] = BitmapColor( (sal_uInt8
) ( (double) pNode
->nRed
/ pNode
->nCount
),
208 (sal_uInt8
) ( (double) pNode
->nGreen
/ pNode
->nCount
),
209 (sal_uInt8
) ( (double) pNode
->nBlue
/ pNode
->nCount
) );
211 else for(OctreeNode
* i
: pNode
->pChild
)
217 void Octree::GetPalIndex( NODE
* pNode
)
220 nPalIndex
= pNode
->nPalIndex
;
223 const sal_uLong nShift
= 7 - nLevel
;
224 const sal_uInt8 cMask
= pImplMask
[ nLevel
++ ];
225 const sal_uLong nIndex
= ( ( ( pColor
->GetRed() & cMask
) >> nShift
) << 2 ) |
226 ( ( ( pColor
->GetGreen() & cMask
) >> nShift
) << 1 ) |
227 ( ( pColor
->GetBlue() & cMask
) >> nShift
);
229 GetPalIndex( pNode
->pChild
[ nIndex
] );
233 InverseColorMap::InverseColorMap( const BitmapPalette
& rPal
) :
234 nBits( 8 - OCTREE_BITS
)
236 const int nColorMax
= 1 << OCTREE_BITS
;
237 const unsigned long xsqr
= 1 << ( nBits
<< 1 );
238 const unsigned long xsqr2
= xsqr
<< 1;
239 const int nColors
= rPal
.GetEntryCount();
240 const long x
= 1 << nBits
;
241 const long x2
= x
>> 1;
245 ImplCreateBuffers( nColorMax
);
247 for( int nIndex
= 0; nIndex
< nColors
; nIndex
++ )
249 const BitmapColor
& rColor
= rPal
[ (sal_uInt16
) nIndex
];
250 const long cRed
= rColor
.GetRed();
251 const long cGreen
= rColor
.GetGreen();
252 const long cBlue
= rColor
.GetBlue();
254 long rdist
= cRed
- x2
;
255 long gdist
= cGreen
- x2
;
256 long bdist
= cBlue
- x2
;
257 rdist
= rdist
*rdist
+ gdist
*gdist
+ bdist
*bdist
;
259 const long crinc
= ( xsqr
- ( cRed
<< nBits
) ) << 1;
260 const long cginc
= ( xsqr
- ( cGreen
<< nBits
) ) << 1;
261 const long cbinc
= ( xsqr
- ( cBlue
<< nBits
) ) << 1;
263 sal_uLong
* cdp
= reinterpret_cast<sal_uLong
*>(pBuffer
);
264 sal_uInt8
* crgbp
= pMap
;
266 for( r
= 0, rxx
= crinc
; r
< nColorMax
; rdist
+= rxx
, r
++, rxx
+= xsqr2
)
268 for( g
= 0, gdist
= rdist
, gxx
= cginc
; g
< nColorMax
; gdist
+= gxx
, g
++, gxx
+= xsqr2
)
270 for( b
= 0, bdist
= gdist
, bxx
= cbinc
; b
< nColorMax
; bdist
+= bxx
, b
++, cdp
++, crgbp
++, bxx
+= xsqr2
)
271 if ( !nIndex
|| ( (long) *cdp
) > bdist
)
274 *crgbp
= (sal_uInt8
) nIndex
;
281 InverseColorMap::~InverseColorMap()
283 rtl_freeMemory( pBuffer
);
284 rtl_freeMemory( pMap
);
287 void InverseColorMap::ImplCreateBuffers( const sal_uLong nMax
)
289 const sal_uLong nCount
= nMax
* nMax
* nMax
;
290 const sal_uLong nSize
= nCount
* sizeof( sal_uLong
);
292 pMap
= static_cast<sal_uInt8
*>(rtl_allocateMemory( nCount
));
293 memset( pMap
, 0x00, nCount
);
295 pBuffer
= static_cast<sal_uInt8
*>(rtl_allocateMemory( nSize
));
296 memset( pBuffer
, 0xff, nSize
);
299 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */