All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.squareup.gifencoder.OctTreeQuantizer Maven / Gradle / Ivy

/*
 * Copyright (C) 2015 Square, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.squareup.gifencoder;

import java.util.HashSet;
import java.util.Set;

/**
 * Implements qct-tree quantization.
 * 

* The principle of algorithm: http://www.microsoft.com/msj/archive/S3F1.aspx *

*/ public final class OctTreeQuantizer implements ColorQuantizer { public static final OctTreeQuantizer INSTANCE = new OctTreeQuantizer(); private static final char[] mask = new char[]{0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01}; private int leafCount; private int inIndex; private final Node[] nodeList = new Node[8]; private OctTreeQuantizer() { } @Override public Set quantize(Multiset originalColors, int maxColorCount) { Node node = createNode(0); Set distinctElements = originalColors.getDistinctElements(); for (Color color : distinctElements) { addColor(node, color, 0); while (leafCount > maxColorCount) { reduceTree(); } } HashSet colors = new HashSet<>(); getColorPalette(node, colors); leafCount = 0; inIndex = 0; for (int i = 0; i < 8; i++) { nodeList[i] = null; } return colors; } private boolean addColor(Node node, Color color, int inLevel) { int nIndex, shift; if (node == null) { node = createNode(inLevel); } int red = (int) (color.getComponent(0) * 255); int green = (int) (color.getComponent(1) * 255); int blue = (int) (color.getComponent(2) * 255); if (node.isLeaf) { node.pixelCount++; node.redSum += red; node.greenSum += green; node.blueSum += blue; } else { shift = 7 - inLevel; nIndex = (((red & mask[inLevel]) >> shift) << 2) | (((green & mask[inLevel]) >> shift) << 1) | ((blue & mask[inLevel]) >> shift); Node tmpNode = node.child[nIndex]; if (tmpNode == null) { tmpNode = createNode(inLevel + 1); } node.child[nIndex] = tmpNode; return addColor(node.child[nIndex], color, inLevel + 1); } return true; } private Node createNode(int level) { Node node = new Node(); node.level = level; node.isLeaf = (level == 8); if (node.isLeaf) { leafCount++; } else { node.next = nodeList[level]; nodeList[level] = node; } return node; } private void reduceTree() { int i; int redSum = 0, greenSum = 0, blueSum = 0, count = 0; for (i = 7; i > 0; i--) { if (nodeList[i] != null) break; } Node tmpNode = nodeList[i]; nodeList[i] = tmpNode.next; for (i = 0; i < 8; i++) { if (tmpNode.child[i] != null) { redSum += tmpNode.child[i].redSum; greenSum += tmpNode.child[i].greenSum; blueSum += tmpNode.child[i].blueSum; count += tmpNode.child[i].pixelCount; tmpNode.child[i] = null; leafCount--; } } tmpNode.isLeaf = true; tmpNode.redSum = redSum; tmpNode.greenSum = greenSum; tmpNode.blueSum = blueSum; tmpNode.pixelCount = count; leafCount++; } private void getColorPalette(Node node, Set colors) { if (node.isLeaf) { node.colorIndex = inIndex; node.redSum = node.redSum / node.pixelCount; node.greenSum = node.greenSum / node.pixelCount; node.blueSum = node.blueSum / node.pixelCount; node.pixelCount = 1; inIndex++; double red = (double) node.redSum / 255; double green = (double) node.greenSum / 255; double blue = (double) node.blueSum / 255; colors.add(new Color(red, green, blue)); } else { for (int i = 0; i < 8; i++) { if (node.child[i] != null) { getColorPalette(node.child[i], colors); } } } } private static final class Node { boolean isLeaf; int level; int colorIndex; int redSum; int greenSum; int blueSum; int pixelCount; Node[] child = new Node[8]; Node next; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy