Initial files

This commit is contained in:
2024-04-21 16:38:26 +02:00
parent c69c668ae6
commit cf04700131
554 changed files with 131197 additions and 0 deletions

View File

@@ -0,0 +1,78 @@
using UnityEngine;
using System.Collections;
using System.IO;
using System.Collections.Generic;
using System.Threading;
using System.Text;
using System;
namespace uGIF
{
public class CaptureToGIFCustom : MonoBehaviour
{
public static CaptureToGIFCustom Instance;
public List<Image> Frames = new List<Image>();
public bool stop = false;
[System.NonSerialized]
public byte[] bytes = null;
private void Awake()
{
Instance = this;
}
public IEnumerator Encode (float fps, int quality)
{
bytes = null;
stop = false;
Error.Log("Recording...", Color.green);
yield return new WaitForSeconds(0.1f);
yield return _Encode(fps, quality);
Error.Log("Saving gif...", Color.green);
yield return new WaitForSeconds(0.1f);
yield return WaitForBytes();
}
IEnumerator WaitForBytes() {
while(bytes == null) yield return new WaitForEndOfFrame();
string fileName = string.Format("KF3Viewer_{0}.gif", DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss-fff"));
string savePath = Path.GetFullPath(Path.Combine(Settings.ScreenshotDirectory, fileName));
Directory.CreateDirectory(Settings.ScreenshotDirectory);
File.WriteAllBytes(savePath, bytes);
bytes = null;
Error.Log($"GIF saved: {savePath}", Color.green);
Frames.Clear();
stop = false;
}
public IEnumerator _Encode (float fps, int quality)
{
var ge = new GIFEncoder ();
ge.useGlobalColorTable = true;
ge.repeat = 0;
ge.FPS = fps;
ge.quality = quality;
ge.transparent = new Color32 (0, 0, 0, 0);
ge.dispose = 2;
var stream = new MemoryStream ();
ge.Start (stream);
while (!stop || Frames.Count > 0)
{
if(Frames.Count>0 && Frames[0] != null)
{
Frames[0].Flip();
ge.AddFrame(Frames[0]);
Frames.RemoveAt(0);
}
yield return 0;
}
ge.Finish ();
bytes = stream.GetBuffer ();
stream.Close ();
yield break;
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: fa66f75ff0e8a134b8014ca7a6e65689
timeCreated: 1440680919
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,261 @@
using System;
using System.IO;
using UnityEngine;
using System.Collections.Generic;
namespace uGIF
{
public class GIFEncoder
{
public bool useGlobalColorTable = false;
public Color32? transparent = null;
public int repeat = -1;
public int dispose = -1; // disposal code (-1 = use default)
public int quality = 10; // default sample interval for quantizer
public float FPS {
set {
delay = Mathf.RoundToInt (100f / value);
}
}
public void AddFrame (Image im)
{
if (im == null)
throw new ArgumentNullException ("im");
if (!started)
throw new InvalidOperationException ("Start() must be called before AddFrame()");
if (firstFrame) {
width = im.width;
height = im.height;
}
pixels = im.pixels;
RemapPixels (); // build color table & map pixels
pixels = null;
if (firstFrame) {
WriteLSD (); // logical screen descriptior
WritePalette (); // global color table
if (repeat >= 0) {
// use NS app extension to indicate reps
WriteNetscapeExt ();
}
}
WriteGraphicCtrlExt (); // write graphic control extension
WriteImageDesc (); // image descriptor
if (!firstFrame && !useGlobalColorTable) {
WritePalette (); // local color table
}
WritePixels (); // encode and write pixel data
firstFrame = false;
}
public void Finish ()
{
if (!started)
throw new InvalidOperationException ("Start() must be called before Finish()");
started = false;
ms.WriteByte (0x3b); // gif trailer
ms.Flush ();
// reset for subsequent use
transIndex = 0;
pixels = null;
indexedPixels = null;
prevIndexedPixels = null;
colorTab = null;
firstFrame = true;
nq = null;
}
public void Start (MemoryStream os)
{
if (os == null)
throw new ArgumentNullException ("os");
ms = os;
started = true;
WriteString ("GIF89a"); // header
}
void RemapPixels ()
{
int len = pixels.Length;
indexedPixels = new byte[len];
if (firstFrame || !useGlobalColorTable) {
// initialize quantizer
nq = new NeuQuant (pixels, len, quality);
colorTab = nq.Process (); // create reduced palette
}
for (int i = 0; i < len; i++) {
int index = nq.Map (pixels [i].r & 0xff, pixels [i].g & 0xff, pixels [i].b & 0xff);
usedEntry [index] = true;
indexedPixels [i] = (byte)index;
if (dispose == 1 && prevIndexedPixels != null) {
if (indexedPixels [i] == prevIndexedPixels [i]) {
indexedPixels [i] = (byte)transIndex;
} else {
prevIndexedPixels [i] = (byte)index;
}
}
}
colorDepth = 8;
palSize = 7;
// get closest match to transparent color if specified
if (transparent.HasValue) {
var c = transparent.Value;
//transIndex = FindClosest(transparent);
transIndex = nq.Map (c.b, c.g, c.r);
}
if (dispose == 1 && prevIndexedPixels == null)
prevIndexedPixels = indexedPixels.Clone () as byte[];
}
int FindClosest (Color32 c)
{
if (colorTab == null)
return -1;
int r = c.r;
int g = c.g;
int b = c.b;
int minpos = 0;
int dmin = 256 * 256 * 256;
int len = colorTab.Length;
for (int i = 0; i < len;) {
int dr = r - (colorTab [i++] & 0xff);
int dg = g - (colorTab [i++] & 0xff);
int db = b - (colorTab [i] & 0xff);
int d = dr * dr + dg * dg + db * db;
int index = i / 3;
if (usedEntry [index] && (d < dmin)) {
dmin = d;
minpos = index;
}
i++;
}
return minpos;
}
void WriteGraphicCtrlExt ()
{
ms.WriteByte (0x21); // extension introducer
ms.WriteByte (0xf9); // GCE label
ms.WriteByte (4); // data block size
int transp, disp;
if (transparent == null) {
transp = 0;
disp = 0; // dispose = no action
} else {
transp = 1;
disp = 2; // force clear if using transparent color
}
if (dispose >= 0) {
disp = dispose & 7; // user override
}
disp <<= 2;
// packed fields
ms.WriteByte (Convert.ToByte (0 | // 1:3 reserved
disp | // 4:6 disposal
0 | // 7 user input - 0 = none
transp)); // 8 transparency flag
WriteShort (delay); // delay x 1/100 sec
ms.WriteByte (Convert.ToByte (transIndex)); // transparent color index
ms.WriteByte (0); // block terminator
}
void WriteImageDesc ()
{
ms.WriteByte (0x2c); // image separator
WriteShort (0); // image position x,y = 0,0
WriteShort (0);
WriteShort (width); // image size
WriteShort (height);
// no LCT - GCT is used for first (or only) frame
ms.WriteByte (0);
}
void WriteLSD ()
{
// logical screen size
WriteShort (width);
WriteShort (height);
// packed fields
ms.WriteByte (Convert.ToByte (0x80 | // 1 : global color table flag = 1 (gct used)
0x70 | // 2-4 : color resolution = 7
0x00 | // 5 : gct sort flag = 0
palSize)); // 6-8 : gct size
ms.WriteByte (0); // background color index
ms.WriteByte (0); // pixel aspect ratio - assume 1:1
}
void WriteNetscapeExt ()
{
ms.WriteByte (0x21); // extension introducer
ms.WriteByte (0xff); // app extension label
ms.WriteByte (11); // block size
WriteString ("NETSCAPE" + "2.0"); // app id + auth code
ms.WriteByte (3); // sub-block size
ms.WriteByte (1); // loop sub-block id
WriteShort (repeat); // loop count (extra iterations, 0=repeat forever)
ms.WriteByte (0); // block terminator
}
void WritePalette ()
{
ms.Write (colorTab, 0, colorTab.Length);
int n = (3 * 256) - colorTab.Length;
for (int i = 0; i < n; i++) {
ms.WriteByte (0);
}
}
void WritePixels ()
{
LZWEncoder encoder = new LZWEncoder (width, height, indexedPixels, colorDepth);
encoder.Encode (ms);
}
void WriteShort (int value)
{
ms.WriteByte (Convert.ToByte (value & 0xff));
ms.WriteByte (Convert.ToByte ((value >> 8) & 0xff));
}
void WriteString (String s)
{
char[] chars = s.ToCharArray ();
for (int i = 0; i < chars.Length; i++) {
ms.WriteByte ((byte)chars [i]);
}
}
int delay = 0;
int width;
int height;
int transIndex;
bool started = false;
MemoryStream ms;
Color32[] pixels;
byte[] indexedPixels;
byte[] prevIndexedPixels;
int colorDepth;
byte[] colorTab;
bool[] usedEntry = new bool[256]; // active palette entries
int palSize = 7; // color table size (bits-1)
bool firstFrame = true;
NeuQuant nq;
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: f9cefdd8311054a0ca0732d817079222
timeCreated: 1440680959
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,110 @@
using UnityEngine;
using System.Collections;
namespace uGIF
{
public class Image
{
public int width;
public int height;
public Color32[] pixels;
public Image (Texture2D f)
{
pixels = f.GetPixels32 ();
width = f.width;
height = f.height;
}
public Image (Image image)
{
pixels = image.pixels.Clone () as Color32[];
width = image.width;
height = image.height;
}
public Image (int width, int height)
{
this.width = width;
this.height = height;
pixels = new Color32[width * height];
}
public void DrawImage (Image image, int i, int i2)
{
throw new System.NotImplementedException ();
}
public Color32 GetPixel (int tw, int th)
{
var index = (th * width) + tw;
return pixels [index];
}
public void Flip ()
{
for (var y = 0; y < height/2; y++) {
for (var x = 0; x < width; x++) {
var top = y * width + x;
var bottom = (height - y - 1) * width + x;
var temp = pixels [top];
pixels [top] = pixels [bottom];
pixels [bottom] = temp;
}
}
}
public void Resize (int scale)
{
if (scale <= 1)
return;
var newWidth = width / scale;
var newHeight = height / scale;
var newColors = new Color32[newWidth * newHeight];
for (var y=0; y<newHeight; y++) {
for (var x=0; x<newWidth; x++) {
newColors [(y * newWidth) + x] = pixels [(y * scale) * width + (x * scale)];
}
}
pixels = newColors;
height = newHeight;
width = newWidth;
}
public void ResizeBilinear (int newWidth, int newHeight)
{
if (newWidth == width && newHeight == height)
return;
var texColors = pixels;
var newColors = new Color32[newWidth * newHeight];
var ratioX = 1.0f / ((float)newWidth / (width - 1));
var ratioY = 1.0f / ((float)newHeight / (height - 1));
var w = width;
var w2 = newWidth;
for (var y = 0; y < newHeight; y++) {
var yFloor = Mathf.FloorToInt (y * ratioY);
var y1 = yFloor * w;
var y2 = (yFloor + 1) * w;
var yw = y * w2;
for (var x = 0; x < w2; x++) {
int xFloor = (int)Mathf.Floor (x * ratioX);
var xLerp = x * ratioX - xFloor;
newColors [yw + x] = ColorLerpUnclamped (ColorLerpUnclamped (texColors [y1 + xFloor], texColors [y1 + xFloor + 1], xLerp), ColorLerpUnclamped (texColors [y2 + xFloor], texColors [y2 + xFloor + 1], xLerp), y * ratioY - yFloor);
}
}
pixels = newColors;
height = newHeight;
width = newWidth;
}
Color32 ColorLerpUnclamped (Color A, Color B, float P)
{
return new Color (A.r + (B.r - A.r) * P, A.g + (B.g - A.g) * P, A.b + (B.b - A.b) * P, A.a + (B.a - A.a) * P);
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: e6a459d4e9025482c87c0f3bdac39d24
timeCreated: 1440596375
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2015 Simon Wittber
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: cb1ea92ee72e4c04dbdb953b6283e116
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,294 @@
using System;
using System.IO;
namespace uGIF
{
public class LZWEncoder
{
static readonly int EOF = -1;
byte[] pixAry;
int initCodeSize;
int curPixel;
// GIFCOMPR.C - GIF Image compression routines
//
// Lempel-Ziv compression based on 'compress'. GIF modifications by
// David Rowley (mgardi@watdcsu.waterloo.edu)
// General DEFINEs
static readonly int BITS = 12;
static readonly int HSIZE = 5003; // 80% occupancy
// GIF Image compression - modified 'compress'
//
// Based on: compress.c - File compression ala IEEE Computer, June 1984.
//
// By Authors: Spencer W. Thomas (decvax!harpo!utah-cs!utah-gr!thomas)
// Jim McKie (decvax!mcvax!jim)
// Steve Davies (decvax!vax135!petsd!peora!srd)
// Ken Turkowski (decvax!decwrl!turtlevax!ken)
// James A. Woods (decvax!ihnp4!ames!jaw)
// Joe Orost (decvax!vax135!petsd!joe)
int n_bits; // number of bits/code
int maxbits = BITS; // user settable max # bits/code
int maxcode; // maximum code, given n_bits
int maxmaxcode = 1 << BITS; // should NEVER generate this code
int[] htab = new int[HSIZE];
int[] codetab = new int[HSIZE];
int hsize = HSIZE; // for dynamic table sizing
int free_ent = 0; // first unused entry
// block compression parameters -- after all codes are used up,
// and compression rate changes, start over.
bool clear_flg = false;
// Algorithm: use open addressing double hashing (no chaining) on the
// prefix code / next character combination. We do a variant of Knuth's
// algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime
// secondary probe. Here, the modular division first probe is gives way
// to a faster exclusive-or manipulation. Also do block compression with
// an adaptive reset, whereby the code table is cleared when the compression
// ratio decreases, but after the table fills. The variable-length output
// codes are re-sized at this point, and a special CLEAR code is generated
// for the decompressor. Late addition: construct the table according to
// file size for noticeable speed improvement on small files. Please direct
// questions about this implementation to ames!jaw.
int g_init_bits;
int ClearCode;
int EOFCode;
// output
//
// Output the given code.
// Inputs:
// code: A n_bits-bit integer. If == -1, then EOF. This assumes
// that n_bits =< wordsize - 1.
// Outputs:
// Outputs code to the file.
// Assumptions:
// Chars are 8 bits long.
// Algorithm:
// Maintain a BITS character long buffer (so that 8 codes will
// fit in it exactly). Use the VAX insv instruction to insert each
// code in turn. When the buffer fills up empty it and start over.
int cur_accum = 0;
int cur_bits = 0;
int[] masks =
{
0x0000,
0x0001,
0x0003,
0x0007,
0x000F,
0x001F,
0x003F,
0x007F,
0x00FF,
0x01FF,
0x03FF,
0x07FF,
0x0FFF,
0x1FFF,
0x3FFF,
0x7FFF,
0xFFFF };
// Number of characters so far in this 'packet'
int a_count;
// Define the storage for the packet accumulator
byte[] accum = new byte[256];
//----------------------------------------------------------------------------
public LZWEncoder (int width, int height, byte[] pixels, int color_depth)
{
pixAry = pixels;
initCodeSize = Math.Max (2, color_depth);
}
// Add a character to the end of the current packet, and if it is 254
// characters, flush the packet to disk.
void Add (byte c, Stream outs)
{
accum [a_count++] = c;
if (a_count >= 254)
Flush (outs);
}
// Clear out the hash table
// table clear for block compress
void ClearTable (Stream outs)
{
ResetCodeTable (hsize);
free_ent = ClearCode + 2;
clear_flg = true;
Output (ClearCode, outs);
}
// reset code table
void ResetCodeTable (int hsize)
{
for (int i = 0; i < hsize; ++i)
htab [i] = -1;
}
void Compress (int init_bits, Stream outs)
{
int fcode;
int i /* = 0 */;
int c;
int ent;
int disp;
int hsize_reg;
int hshift;
// Set up the globals: g_init_bits - initial number of bits
g_init_bits = init_bits;
// Set up the necessary values
clear_flg = false;
n_bits = g_init_bits;
maxcode = MaxCode (n_bits);
ClearCode = 1 << (init_bits - 1);
EOFCode = ClearCode + 1;
free_ent = ClearCode + 2;
a_count = 0; // clear packet
ent = NextPixel ();
hshift = 0;
for (fcode = hsize; fcode < 65536; fcode *= 2)
++hshift;
hshift = 8 - hshift; // set hash code range bound
hsize_reg = hsize;
ResetCodeTable (hsize_reg); // clear hash table
Output (ClearCode, outs);
outer_loop :
while ((c = NextPixel()) != EOF) {
fcode = (c << maxbits) + ent;
i = (c << hshift) ^ ent; // xor hashing
if (htab [i] == fcode) {
ent = codetab [i];
continue;
} else if (htab [i] >= 0) { // non-empty slot
disp = hsize_reg - i; // secondary hash (after G. Knott)
if (i == 0)
disp = 1;
do {
if ((i -= disp) < 0)
i += hsize_reg;
if (htab [i] == fcode) {
ent = codetab [i];
goto outer_loop;
}
} while (htab[i] >= 0);
}
Output (ent, outs);
ent = c;
if (free_ent < maxmaxcode) {
codetab [i] = free_ent++; // code -> hashtable
htab [i] = fcode;
} else
ClearTable (outs);
}
// Put out the final code.
Output (ent, outs);
Output (EOFCode, outs);
}
//----------------------------------------------------------------------------
public void Encode (Stream os)
{
os.WriteByte (Convert.ToByte (initCodeSize)); // write "initial code size" byte
curPixel = 0;
Compress (initCodeSize + 1, os); // compress and write the pixel data
os.WriteByte (0); // write block terminator
}
// Flush the packet to disk, and reset the accumulator
void Flush (Stream outs)
{
if (a_count > 0) {
outs.WriteByte (Convert.ToByte (a_count));
outs.Write (accum, 0, a_count);
a_count = 0;
}
}
int MaxCode (int n_bits)
{
return (1 << n_bits) - 1;
}
//----------------------------------------------------------------------------
// Return the next pixel from the image
//----------------------------------------------------------------------------
int NextPixel ()
{
if (curPixel == pixAry.Length)
return EOF;
curPixel++;
return pixAry [curPixel - 1] & 0xff;
}
void Output (int code, Stream outs)
{
cur_accum &= masks [cur_bits];
if (cur_bits > 0)
cur_accum |= (code << cur_bits);
else
cur_accum = code;
cur_bits += n_bits;
while (cur_bits >= 8) {
Add ((byte)(cur_accum & 0xff), outs);
cur_accum >>= 8;
cur_bits -= 8;
}
// If the next entry is going to be too big for the code size,
// then increase it, if possible.
if (free_ent > maxcode || clear_flg) {
if (clear_flg) {
maxcode = MaxCode (n_bits = g_init_bits);
clear_flg = false;
} else {
++n_bits;
if (n_bits == maxbits)
maxcode = maxmaxcode;
else
maxcode = MaxCode (n_bits);
}
}
if (code == EOFCode) {
// At EOF, write the rest of the buffer.
while (cur_bits > 0) {
Add ((byte)(cur_accum & 0xff), outs);
cur_accum >>= 8;
cur_bits -= 8;
}
Flush (outs);
}
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: fcb109a1b5481440891b04c6588a6599
timeCreated: 1440596152
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,465 @@
/* NeuQuant Neural-Net Quantization Algorithm
* ------------------------------------------
*
* Copyright (c) 1994 Anthony Dekker
*
* NEUQUANT Neural-Net quantization algorithm by Anthony Dekker, 1994.
* See "Kohonen neural networks for optimal colour quantization"
* in "Network: Computation in Neural Systems" Vol. 5 (1994) pp 351-367.
* for a discussion of the algorithm.
*
* Any party obtaining a copy of these files from the author, directly or
* indirectly, is granted, free of charge, a full and unrestricted irrevocable,
* world-wide, paid up, royalty-free, nonexclusive right and license to deal
* in this software and documentation files (the "Software"), including without
* limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons who receive
* copies from any such party to do so, with the only requirement being
* that this copyright notice remain intact.
*/
// Ported to Java 12/00 K Weiner
using System;
using UnityEngine;
namespace uGIF
{
public class NeuQuant
{
static readonly int netsize = 256; /* number of colours used */
/* four primes near 500 - assume no image has a length so large */
/* that it is divisible by all four primes */
static readonly int prime1 = 499;
static readonly int prime2 = 491;
static readonly int prime3 = 487;
static readonly int prime4 = 503;
static readonly int minpicturebytes = (3 * prime4);
/* minimum size for input image */
/* Program Skeleton
----------------
[select samplefac in range 1..30]
[read image from input file]
pic = (unsigned char*) malloc(3*width*height);
initnet(pic,3*width*height,samplefac);
learn();
unbiasnet();
[write output image header, using writecolourmap(f)]
inxbuild();
write output image using inxsearch(b,g,r) */
/* Network Definitions
------------------- */
static readonly int maxnetpos = (netsize - 1);
static readonly int netbiasshift = 4; /* bias for colour values */
static readonly int ncycles = 100; /* no. of learning cycles */
/* defs for freq and bias */
static readonly int intbiasshift = 16; /* bias for fractions */
static readonly int intbias = (((int)1) << intbiasshift);
static readonly int gammashift = 10; /* gamma = 1024 */
static readonly int gamma = (((int)1) << gammashift);
static readonly int betashift = 10;
static readonly int beta = (intbias >> betashift); /* beta = 1/1024 */
static readonly int betagamma = (intbias << (gammashift - betashift));
/* defs for decreasing radius factor */
static readonly int initrad = (netsize >> 3); /* for 256 cols, radius starts */
static readonly int radiusbiasshift = 6; /* at 32.0 biased by 6 bits */
static readonly int radiusbias = (((int)1) << radiusbiasshift);
static readonly int initradius = (initrad * radiusbias); /* and decreases by a */
static readonly int radiusdec = 30; /* factor of 1/30 each cycle */
/* defs for decreasing alpha factor */
static readonly int alphabiasshift = 10; /* alpha starts at 1.0 */
static readonly int initalpha = (((int)1) << alphabiasshift);
int alphadec; /* biased by 10 bits */
/* radbias and alpharadbias used for radpower calculation */
static readonly int radbiasshift = 8;
static readonly int radbias = (((int)1) << radbiasshift);
static readonly int alpharadbshift = (alphabiasshift + radbiasshift);
static readonly int alpharadbias = (((int)1) << alpharadbshift);
/* Types and Global Variables
-------------------------- */
Color32[] thepicture; /* the input image itself */
int lengthcount; /* lengthcount = H*W*3 */
int samplefac; /* sampling factor 1..30 */
// typedef int pixel[4]; /* BGRc */
int[][] network; /* the network itself - [netsize][4] */
int[] netindex = new int[256];
/* for network lookup - really 256 */
int[] bias = new int[netsize];
/* bias and freq arrays for learning */
int[] freq = new int[netsize];
int[] radpower = new int[initrad];
/* radpower for precomputation */
/* Initialise network in range (0,0,0) to (255,255,255) and set parameters
----------------------------------------------------------------------- */
public NeuQuant (Color32[] thepic, int len, int sample)
{
int i;
int[] p;
thepicture = thepic;
lengthcount = len;
samplefac = sample;
network = new int[netsize][];
for (i = 0; i < netsize; i++) {
network [i] = new int[4];
p = network [i];
p [0] = p [1] = p [2] = (i << (netbiasshift + 8)) / netsize;
freq [i] = intbias / netsize; /* 1/netsize */
bias [i] = 0;
}
}
byte[] ColorMap ()
{
byte[] map = new byte[3 * netsize];
int[] index = new int[netsize];
for (int i = 0; i < netsize; i++)
index [network [i] [3]] = i;
int k = 0;
for (int i = 0; i < netsize; i++) {
int j = index [i];
map [k++] = (byte)(network [j] [0]);
map [k++] = (byte)(network [j] [1]);
map [k++] = (byte)(network [j] [2]);
}
return map;
}
/* Insertion sort of network and building of netindex[0..255] (to do after unbias)
------------------------------------------------------------------------------- */
void Inxbuild ()
{
int i, j, smallpos, smallval;
int[] p;
int[] q;
int previouscol, startpos;
previouscol = 0;
startpos = 0;
for (i = 0; i < netsize; i++) {
p = network [i];
smallpos = i;
smallval = p [1]; /* index on g */
/* find smallest in i..netsize-1 */
for (j = i + 1; j < netsize; j++) {
q = network [j];
if (q [1] < smallval) { /* index on g */
smallpos = j;
smallval = q [1]; /* index on g */
}
}
q = network [smallpos];
/* swap p (i) and q (smallpos) entries */
if (i != smallpos) {
j = q [0];
q [0] = p [0];
p [0] = j;
j = q [1];
q [1] = p [1];
p [1] = j;
j = q [2];
q [2] = p [2];
p [2] = j;
j = q [3];
q [3] = p [3];
p [3] = j;
}
/* smallval entry is now in position i */
if (smallval != previouscol) {
netindex [previouscol] = (startpos + i) >> 1;
for (j = previouscol + 1; j < smallval; j++)
netindex [j] = i;
previouscol = smallval;
startpos = i;
}
}
netindex [previouscol] = (startpos + maxnetpos) >> 1;
for (j = previouscol + 1; j < 256; j++)
netindex [j] = maxnetpos; /* really 256 */
}
/* Main Learning Loop
------------------ */
void Learn ()
{
int i, j, b, g, r;
int radius, rad, alpha, step, delta, samplepixels;
int pix, lim;
if (lengthcount < minpicturebytes)
samplefac = 1;
alphadec = 30 + ((samplefac - 1) / 3);
var p = thepicture;
pix = 0;
lim = lengthcount;
samplepixels = lengthcount / (3 * samplefac);
delta = samplepixels / ncycles;
alpha = initalpha;
radius = initradius;
rad = radius >> radiusbiasshift;
if (rad <= 1)
rad = 0;
for (i = 0; i < rad; i++)
radpower [i] =
alpha * (((rad * rad - i * i) * radbias) / (rad * rad));
//fprintf(stderr,"beginning 1D learning: initial radius=%d\n", rad);
if (lengthcount < minpicturebytes)
step = 3;
else if ((lengthcount % prime1) != 0)
step = 3 * prime1;
else {
if ((lengthcount % prime2) != 0)
step = 3 * prime2;
else {
if ((lengthcount % prime3) != 0)
step = 3 * prime3;
else
step = 3 * prime4;
}
}
i = 0;
while (i < samplepixels) {
b = (p [pix].r & 0xff) << netbiasshift;
g = (p [pix].g & 0xff) << netbiasshift;
r = (p [pix].b & 0xff) << netbiasshift;
j = Contest (b, g, r);
Altersingle (alpha, j, b, g, r);
if (rad != 0)
Alterneigh (rad, j, b, g, r); /* alter neighbours */
pix += step;
if (pix >= lim)
pix -= lengthcount;
i++;
if (delta == 0)
delta = 1;
if (i % delta == 0) {
alpha -= alpha / alphadec;
radius -= radius / radiusdec;
rad = radius >> radiusbiasshift;
if (rad <= 1)
rad = 0;
for (j = 0; j < rad; j++)
radpower [j] =
alpha * (((rad * rad - j * j) * radbias) / (rad * rad));
}
}
}
/* Search for BGR values 0..255 (after net is unbiased) and return colour index
---------------------------------------------------------------------------- */
public int Map (int b, int g, int r)
{
int i, j, dist, a, bestd;
int[] p;
int best;
bestd = 1000; /* biggest possible dist is 256*3 */
best = -1;
i = netindex [g]; /* index on g */
j = i - 1; /* start at netindex[g] and work outwards */
while ((i < netsize) || (j >= 0)) {
if (i < netsize) {
p = network [i];
dist = p [1] - g; /* inx key */
if (dist >= bestd)
i = netsize; /* stop iter */
else {
i++;
if (dist < 0)
dist = -dist;
a = p [0] - b;
if (a < 0)
a = -a;
dist += a;
if (dist < bestd) {
a = p [2] - r;
if (a < 0)
a = -a;
dist += a;
if (dist < bestd) {
bestd = dist;
best = p [3];
}
}
}
}
if (j >= 0) {
p = network [j];
dist = g - p [1]; /* inx key - reverse dif */
if (dist >= bestd)
j = -1; /* stop iter */
else {
j--;
if (dist < 0)
dist = -dist;
a = p [0] - b;
if (a < 0)
a = -a;
dist += a;
if (dist < bestd) {
a = p [2] - r;
if (a < 0)
a = -a;
dist += a;
if (dist < bestd) {
bestd = dist;
best = p [3];
}
}
}
}
}
return (best);
}
public byte[] Process ()
{
Learn ();
Unbiasnet ();
Inxbuild ();
return ColorMap ();
}
/* Unbias network to give byte values 0..255 and record position i to prepare for sort
----------------------------------------------------------------------------------- */
void Unbiasnet ()
{
int i;
for (i = 0; i < netsize; i++) {
network [i] [0] >>= netbiasshift;
network [i] [1] >>= netbiasshift;
network [i] [2] >>= netbiasshift;
network [i] [3] = i; /* record colour no */
}
}
/* Move adjacent neurons by precomputed alpha*(1-((i-j)^2/[r]^2)) in radpower[|i-j|]
--------------------------------------------------------------------------------- */
void Alterneigh (int rad, int i, int b, int g, int r)
{
int j, k, lo, hi, a, m;
int[] p;
lo = i - rad;
if (lo < -1)
lo = -1;
hi = i + rad;
if (hi > netsize)
hi = netsize;
j = i + 1;
k = i - 1;
m = 1;
while ((j < hi) || (k > lo)) {
a = radpower [m++];
if (j < hi) {
p = network [j++];
p [0] -= (a * (p [0] - b)) / alpharadbias;
p [1] -= (a * (p [1] - g)) / alpharadbias;
p [2] -= (a * (p [2] - r)) / alpharadbias;
}
if (k > lo) {
p = network [k--];
p [0] -= (a * (p [0] - b)) / alpharadbias;
p [1] -= (a * (p [1] - g)) / alpharadbias;
p [2] -= (a * (p [2] - r)) / alpharadbias;
}
}
}
/* Move neuron i towards biased (b,g,r) by factor alpha
---------------------------------------------------- */
void Altersingle (int alpha, int i, int b, int g, int r)
{
/* alter hit neuron */
int[] n = network [i];
n [0] -= (alpha * (n [0] - b)) / initalpha;
n [1] -= (alpha * (n [1] - g)) / initalpha;
n [2] -= (alpha * (n [2] - r)) / initalpha;
}
/* Search for biased BGR values
---------------------------- */
int Contest (int b, int g, int r)
{
/* finds closest neuron (min dist) and updates freq */
/* finds best neuron (min dist-bias) and returns position */
/* for frequently chosen neurons, freq[i] is high and bias[i] is negative */
/* bias[i] = gamma*((1/netsize)-freq[i]) */
int i, dist, a, biasdist, betafreq;
int bestpos, bestbiaspos, bestd, bestbiasd;
int[] n;
bestd = ~(((int)1) << 31);
bestbiasd = bestd;
bestpos = -1;
bestbiaspos = bestpos;
for (i = 0; i < netsize; i++) {
n = network [i];
dist = n [0] - b;
if (dist < 0)
dist = -dist;
a = n [1] - g;
if (a < 0)
a = -a;
dist += a;
a = n [2] - r;
if (a < 0)
a = -a;
dist += a;
if (dist < bestd) {
bestd = dist;
bestpos = i;
}
biasdist = dist - ((bias [i]) >> (intbiasshift - netbiasshift));
if (biasdist < bestbiasd) {
bestbiasd = biasdist;
bestbiaspos = i;
}
betafreq = (freq [i] >> betashift);
freq [i] -= betafreq;
bias [i] += (betafreq << gammashift);
}
freq [bestpos] += beta;
bias [bestpos] -= betagamma;
return (bestbiaspos);
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 1a0f39694717a43d4aeddb0f768c205f
timeCreated: 1440596152
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,16 @@
{
"name": "uGIF",
"rootNamespace": "",
"references": [
"GUID:24ad1c085c49dc34dbe16c3d92c6f299"
],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 1cac605065571ce41be4833afb33d352
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant: