android: Update app-specific/MIME type icons
[LibreOffice.git] / vcl / source / bitmap / Octree.cxx
blob98ad8c9fcf5d21f1f8ae4a133cd11086adbabd69
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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/BitmapReadAccess.hxx>
22 #include <bitmap/Octree.hxx>
24 namespace
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)
34 : mnLeafCount(0)
35 , mnLevel(0)
36 , mpReduce(OCTREE_BITS + 1, nullptr)
37 , mnPalIndex(0)
39 const BitmapReadAccess* pAccess = &rReadAcc;
40 sal_uLong nMax(nColors);
42 if (!*pAccess)
43 return;
45 const tools::Long nWidth = pAccess->Width();
46 const tools::Long nHeight = pAccess->Height();
48 if (pAccess->HasPalette())
50 for (tools::Long nY = 0; nY < nHeight; nY++)
52 Scanline pScanline = pAccess->GetScanline(nY);
53 for (tools::Long nX = 0; nX < nWidth; nX++)
55 mnLevel = 0;
56 add(pTree, pAccess->GetPaletteColor(pAccess->GetIndexFromData(pScanline, nX)));
58 while (mnLeafCount > nMax)
59 reduce();
63 else
65 for (tools::Long nY = 0; nY < nHeight; nY++)
67 Scanline pScanline = pAccess->GetScanline(nY);
68 for (tools::Long nX = 0; nX < nWidth; nX++)
70 mnLevel = 0;
71 add(pTree, pAccess->GetPixelFromData(pScanline, nX));
73 while (mnLeafCount > nMax)
74 reduce();
80 Octree::~Octree() {}
82 void Octree::add(std::unique_ptr<OctreeNode>& rpNode, BitmapColor const& color)
84 // possibly generate new nodes
85 if (!rpNode)
87 rpNode.reset(new OctreeNode);
88 rpNode->bLeaf = (OCTREE_BITS == mnLevel);
90 if (rpNode->bLeaf)
91 mnLeafCount++;
92 else
94 rpNode->pNext = mpReduce[mnLevel];
95 mpReduce[mnLevel] = rpNode.get();
99 if (rpNode->bLeaf)
101 rpNode->nCount++;
102 rpNode->nRed += color.GetRed();
103 rpNode->nGreen += color.GetGreen();
104 rpNode->nBlue += color.GetBlue();
106 else
108 const sal_uLong nShift = 7 - mnLevel;
109 const sal_uInt8 cMask = 0x80 >> mnLevel;
110 const sal_uLong nIndex = (((color.GetRed() & cMask) >> nShift) << 2)
111 | (((color.GetGreen() & cMask) >> nShift) << 1)
112 | ((color.GetBlue() & cMask) >> nShift);
114 mnLevel++;
115 add(rpNode->pChild[nIndex], color);
119 void Octree::reduce()
121 OctreeNode* pNode;
122 sal_uLong nRedSum = 0;
123 sal_uLong nGreenSum = 0;
124 sal_uLong nBlueSum = 0;
125 sal_uLong nChildren = 0;
127 sal_uLong nIndex = OCTREE_BITS - 1;
128 while (nIndex > 0 && !mpReduce[nIndex])
130 nIndex--;
133 pNode = mpReduce[nIndex];
134 mpReduce[nIndex] = pNode->pNext;
136 for (unsigned int i = 0; i < 8; i++)
138 if (pNode->pChild[i])
140 OctreeNode* pChild = pNode->pChild[i].get();
142 nRedSum += pChild->nRed;
143 nGreenSum += pChild->nGreen;
144 nBlueSum += pChild->nBlue;
145 pNode->nCount += pChild->nCount;
147 pNode->pChild[i].reset();
148 nChildren++;
152 pNode->bLeaf = true;
153 pNode->nRed = nRedSum;
154 pNode->nGreen = nGreenSum;
155 pNode->nBlue = nBlueSum;
156 mnLeafCount -= --nChildren;
159 void Octree::CreatePalette(OctreeNode* pNode)
161 if (pNode->bLeaf)
163 pNode->nPalIndex = mnPalIndex;
164 maPalette[mnPalIndex++] = BitmapColor(sal_uInt8(double(pNode->nRed) / pNode->nCount),
165 sal_uInt8(double(pNode->nGreen) / pNode->nCount),
166 sal_uInt8(double(pNode->nBlue) / pNode->nCount));
168 else
170 for (auto const& i : pNode->pChild)
172 if (i)
174 CreatePalette(i.get());
180 void Octree::GetPalIndex(const OctreeNode* pNode, BitmapColor const& color)
182 if (pNode->bLeaf)
183 mnPalIndex = pNode->nPalIndex;
184 else
186 const sal_uLong nShift = 7 - mnLevel;
187 const sal_uInt8 cMask = 0x80 >> mnLevel;
188 mnLevel++;
189 const sal_uLong nIndex = (((color.GetRed() & cMask) >> nShift) << 2)
190 | (((color.GetGreen() & cMask) >> nShift) << 1)
191 | ((color.GetBlue() & cMask) >> nShift);
193 GetPalIndex(pNode->pChild[nIndex].get(), color);
197 const BitmapPalette& Octree::GetPalette()
199 maPalette.SetEntryCount(sal_uInt16(mnLeafCount));
200 mnPalIndex = 0;
201 CreatePalette(pTree.get());
202 return maPalette;
205 sal_uInt16 Octree::GetBestPaletteIndex(const BitmapColor& rColor)
207 mnPalIndex = 65535;
208 mnLevel = 0;
209 GetPalIndex(pTree.get(), rColor);
210 return mnPalIndex;
213 constexpr int nColorMax = 1 << OCTREE_BITS;
215 InverseColorMap::InverseColorMap(const BitmapPalette& rPal)
217 const unsigned long xsqr = 1 << (gnBits << 1);
218 const unsigned long xsqr2 = xsqr << 1;
219 const int nColors = rPal.GetEntryCount();
220 const tools::Long x = 1 << gnBits;
221 const tools::Long x2 = x >> 1;
222 sal_uLong r, g, b;
223 tools::Long rxx, gxx, bxx;
225 ImplCreateBuffers();
227 for (int nIndex = 0; nIndex < nColors; nIndex++)
229 const BitmapColor& rColor = rPal[static_cast<sal_uInt16>(nIndex)];
230 const tools::Long cRed = rColor.GetRed();
231 const tools::Long cGreen = rColor.GetGreen();
232 const tools::Long cBlue = rColor.GetBlue();
234 tools::Long rdist = cRed - x2;
235 tools::Long gdist = cGreen - x2;
236 tools::Long bdist = cBlue - x2;
237 rdist = rdist * rdist + gdist * gdist + bdist * bdist;
239 const tools::Long crinc = (xsqr - (cRed << gnBits)) << 1;
240 const tools::Long cginc = (xsqr - (cGreen << gnBits)) << 1;
241 const tools::Long cbinc = (xsqr - (cBlue << gnBits)) << 1;
243 sal_uLong* cdp = reinterpret_cast<sal_uLong*>(mpBuffer.data());
244 sal_uInt8* crgbp = mpMap.data();
246 for (r = 0, rxx = crinc; r < nColorMax; rdist += rxx, r++, rxx += xsqr2)
248 for (g = 0, gdist = rdist, gxx = cginc; g < nColorMax; gdist += gxx, g++, gxx += xsqr2)
250 for (b = 0, bdist = gdist, bxx = cbinc; b < nColorMax;
251 bdist += bxx, b++, cdp++, crgbp++, bxx += xsqr2)
252 if (!nIndex || static_cast<tools::Long>(*cdp) > bdist)
254 *cdp = bdist;
255 *crgbp = static_cast<sal_uInt8>(nIndex);
262 InverseColorMap::~InverseColorMap() {}
264 void InverseColorMap::ImplCreateBuffers()
266 const sal_uLong nCount = nColorMax * nColorMax * nColorMax;
267 const sal_uLong nSize = nCount * sizeof(sal_uLong);
269 mpMap.resize(nCount, 0x00);
270 mpBuffer.resize(nSize, 0xff);
273 sal_uInt16 InverseColorMap::GetBestPaletteIndex(const BitmapColor& rColor)
275 return mpMap[((static_cast<sal_uLong>(rColor.GetRed()) >> gnBits) << OCTREE_BITS_1)
276 | ((static_cast<sal_uLong>(rColor.GetGreen()) >> gnBits) << OCTREE_BITS)
277 | (static_cast<sal_uLong>(rColor.GetBlue()) >> gnBits)];
280 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */