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 .
20 #include <vcl/bitmapaccess.hxx>
22 #include <bitmap/Octree.hxx>
26 constexpr size_t OCTREE_BITS
= 5;
27 constexpr size_t OCTREE_BITS_1
= 10;
29 constexpr sal_uLong gnBits
= 8 - OCTREE_BITS
;
31 } // end anonymous namespace
33 Octree::Octree(const BitmapReadAccess
& rReadAcc
, sal_uLong nColors
)
36 , mpReduce(OCTREE_BITS
+ 1, nullptr)
41 sal_uLong
nMax(nColors
);
45 const long nWidth
= mpAccess
->Width();
46 const long nHeight
= mpAccess
->Height();
48 if (mpAccess
->HasPalette())
50 for (long nY
= 0; nY
< nHeight
; nY
++)
52 Scanline pScanline
= mpAccess
->GetScanline(nY
);
53 for (long nX
= 0; nX
< nWidth
; nX
++)
55 mpColor
= &mpAccess
->GetPaletteColor(mpAccess
->GetIndexFromData(pScanline
, nX
));
59 while (mnLeafCount
> nMax
)
70 for (long nY
= 0; nY
< nHeight
; nY
++)
72 Scanline pScanline
= mpAccess
->GetScanline(nY
);
73 for (long nX
= 0; nX
< nWidth
; nX
++)
75 aColor
= mpAccess
->GetPixelFromData(pScanline
, nX
);
79 while (mnLeafCount
> nMax
)
89 void Octree::add(std::unique_ptr
<OctreeNode
>& rpNode
)
91 // possibly generate new nodes
94 rpNode
.reset(new OctreeNode
);
95 rpNode
->bLeaf
= (OCTREE_BITS
== mnLevel
);
101 rpNode
->pNext
= mpReduce
[mnLevel
];
102 mpReduce
[mnLevel
] = rpNode
.get();
109 rpNode
->nRed
+= mpColor
->GetRed();
110 rpNode
->nGreen
+= mpColor
->GetGreen();
111 rpNode
->nBlue
+= mpColor
->GetBlue();
115 const sal_uLong nShift
= 7 - mnLevel
;
116 const sal_uInt8 cMask
= 0x80 >> mnLevel
;
117 const sal_uLong nIndex
= (((mpColor
->GetRed() & cMask
) >> nShift
) << 2)
118 | (((mpColor
->GetGreen() & cMask
) >> nShift
) << 1)
119 | ((mpColor
->GetBlue() & cMask
) >> nShift
);
122 add(rpNode
->pChild
[nIndex
]);
126 void Octree::reduce()
129 sal_uLong nRedSum
= 0;
130 sal_uLong nGreenSum
= 0;
131 sal_uLong nBlueSum
= 0;
132 sal_uLong nChildren
= 0;
134 sal_uLong nIndex
= OCTREE_BITS
- 1;
135 while (nIndex
> 0 && !mpReduce
[nIndex
])
140 pNode
= mpReduce
[nIndex
];
141 mpReduce
[nIndex
] = pNode
->pNext
;
143 for (sal_uLong i
= 0; i
< 8; i
++)
145 if (pNode
->pChild
[i
])
147 OctreeNode
* pChild
= pNode
->pChild
[i
].get();
149 nRedSum
+= pChild
->nRed
;
150 nGreenSum
+= pChild
->nGreen
;
151 nBlueSum
+= pChild
->nBlue
;
152 pNode
->nCount
+= pChild
->nCount
;
154 pNode
->pChild
[i
].reset();
160 pNode
->nRed
= nRedSum
;
161 pNode
->nGreen
= nGreenSum
;
162 pNode
->nBlue
= nBlueSum
;
163 mnLeafCount
-= --nChildren
;
166 void Octree::CreatePalette(OctreeNode
* pNode
)
170 pNode
->nPalIndex
= mnPalIndex
;
171 maPalette
[mnPalIndex
++] = BitmapColor(sal_uInt8(double(pNode
->nRed
) / pNode
->nCount
),
172 sal_uInt8(double(pNode
->nGreen
) / pNode
->nCount
),
173 sal_uInt8(double(pNode
->nBlue
) / pNode
->nCount
));
177 for (auto const& i
: pNode
->pChild
)
181 CreatePalette(i
.get());
187 void Octree::GetPalIndex(const OctreeNode
* pNode
)
190 mnPalIndex
= pNode
->nPalIndex
;
193 const sal_uLong nShift
= 7 - mnLevel
;
194 const sal_uInt8 cMask
= 0x80 >> mnLevel
;
196 const sal_uLong nIndex
= (((mpColor
->GetRed() & cMask
) >> nShift
) << 2)
197 | (((mpColor
->GetGreen() & cMask
) >> nShift
) << 1)
198 | ((mpColor
->GetBlue() & cMask
) >> nShift
);
200 GetPalIndex(pNode
->pChild
[nIndex
].get());
204 const BitmapPalette
& Octree::GetPalette()
206 maPalette
.SetEntryCount(sal_uInt16(mnLeafCount
));
208 CreatePalette(pTree
.get());
212 sal_uInt16
Octree::GetBestPaletteIndex(const BitmapColor
& rColor
)
217 GetPalIndex(pTree
.get());
221 constexpr int nColorMax
= 1 << OCTREE_BITS
;
223 InverseColorMap::InverseColorMap(const BitmapPalette
& rPal
)
225 const unsigned long xsqr
= 1 << (gnBits
<< 1);
226 const unsigned long xsqr2
= xsqr
<< 1;
227 const int nColors
= rPal
.GetEntryCount();
228 const long x
= 1 << gnBits
;
229 const long x2
= x
>> 1;
235 for (int nIndex
= 0; nIndex
< nColors
; nIndex
++)
237 const BitmapColor
& rColor
= rPal
[static_cast<sal_uInt16
>(nIndex
)];
238 const long cRed
= rColor
.GetRed();
239 const long cGreen
= rColor
.GetGreen();
240 const long cBlue
= rColor
.GetBlue();
242 long rdist
= cRed
- x2
;
243 long gdist
= cGreen
- x2
;
244 long bdist
= cBlue
- x2
;
245 rdist
= rdist
* rdist
+ gdist
* gdist
+ bdist
* bdist
;
247 const long crinc
= (xsqr
- (cRed
<< gnBits
)) << 1;
248 const long cginc
= (xsqr
- (cGreen
<< gnBits
)) << 1;
249 const long cbinc
= (xsqr
- (cBlue
<< gnBits
)) << 1;
251 sal_uLong
* cdp
= reinterpret_cast<sal_uLong
*>(mpBuffer
.data());
252 sal_uInt8
* crgbp
= mpMap
.data();
254 for (r
= 0, rxx
= crinc
; r
< nColorMax
; rdist
+= rxx
, r
++, rxx
+= xsqr2
)
256 for (g
= 0, gdist
= rdist
, gxx
= cginc
; g
< nColorMax
; gdist
+= gxx
, g
++, gxx
+= xsqr2
)
258 for (b
= 0, bdist
= gdist
, bxx
= cbinc
; b
< nColorMax
;
259 bdist
+= bxx
, b
++, cdp
++, crgbp
++, bxx
+= xsqr2
)
260 if (!nIndex
|| static_cast<long>(*cdp
) > bdist
)
263 *crgbp
= static_cast<sal_uInt8
>(nIndex
);
270 InverseColorMap::~InverseColorMap() {}
272 void InverseColorMap::ImplCreateBuffers()
274 const sal_uLong nCount
= nColorMax
* nColorMax
* nColorMax
;
275 const sal_uLong nSize
= nCount
* sizeof(sal_uLong
);
277 mpMap
.resize(nCount
, 0x00);
278 mpBuffer
.resize(nSize
, 0xff);
281 sal_uInt16
InverseColorMap::GetBestPaletteIndex(const BitmapColor
& rColor
)
283 return mpMap
[((static_cast<sal_uLong
>(rColor
.GetRed()) >> gnBits
) << OCTREE_BITS_1
)
284 | ((static_cast<sal_uLong
>(rColor
.GetGreen()) >> gnBits
) << OCTREE_BITS
)
285 | (static_cast<sal_uLong
>(rColor
.GetBlue()) >> gnBits
)];
288 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */