Fix #646 Migrate to arsd for image reading

This also removes dimage from 3rdparty
And adds additional image formats that could be read!
This commit is contained in:
Grim Maple 2023-05-19 18:56:09 +03:00
parent b83c59ca6e
commit 663b7dfd73
14 changed files with 14 additions and 3912 deletions

View File

@ -1,243 +0,0 @@
/*
Copyright (c) 2015 Timur Gafarov
Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
// dimage is actually stripped out part of dlib - just to support reading PNG and JPEG
module dimage.array; //dlib.container.array
import dimage.memory;
/*
* GC-free dynamic array implementation.
* Very efficient for small-sized arrays.
*/
struct DynamicArray(T, size_t chunkSize = 32)
{
T[chunkSize] staticStorage;
T[] dynamicStorage;
uint numChunks = 0;
uint pos = 0;
T* storage()
{
if (numChunks == 0)
return staticStorage.ptr;
else
return dynamicStorage.ptr;
}
void addChunk()
{
if (numChunks == 0)
{
dynamicStorage = New!(T[])(chunkSize);
}
else
{
reallocateArray(
dynamicStorage,
dynamicStorage.length + chunkSize);
}
numChunks++;
}
void shiftRight()
{
append(T.init);
for(uint i = pos-1; i > 0; i--)
{
storage[i] = storage[i-1];
}
}
void shiftLeft(uint n)
{
for(uint i = 0; i < pos; i++)
{
if (n + i < pos)
storage[i] = storage[n + i];
else
storage[i] = T.init;
}
}
void append(T c)
{
if (numChunks == 0)
{
staticStorage[pos] = c;
pos++;
if (pos == chunkSize)
{
addChunk();
foreach(i, ref v; dynamicStorage)
v = staticStorage[i];
}
}
else
{
if (pos == dynamicStorage.length)
addChunk();
dynamicStorage[pos] = c;
pos++;
}
}
void appendLeft(T c)
{
shiftRight();
storage[0] = c;
}
void append(const(T)[] s)
{
foreach(c; s)
append(cast(T)c);
}
void appendLeft(const(T)[] s)
{
foreach(c; s)
appendLeft(cast(T)c);
}
auto opCatAssign(T c)
{
append(c);
return this;
}
auto opCatAssign(const(T)[] s)
{
append(s);
return this;
}
uint remove(uint n)
{
if (pos == n)
{
pos = 0;
return n;
}
else if (pos >= n)
{
pos -= n;
return n;
}
else
{
n = pos;
pos = 0;
return n;
}
}
uint removeLeft(uint n)
{
if (pos == n)
{
pos = 0;
return n;
}
else if (pos > n)
{
shiftLeft(n);
pos -= n;
return n;
}
else
{
n = pos;
pos = 0;
return n;
}
}
size_t length()
{
return pos;
}
T[] data()
{
return storage[0..pos];
}
T opIndex(size_t index)
{
return data[index];
}
T opIndexAssign(T t, size_t index)
{
data[index] = t;
return t;
}
int opApply(int delegate(size_t i, ref T) dg)
{
foreach(i, ref v; data)
{
dg(i, v);
}
return 0;
}
int opApply(int delegate(ref T) dg)
{
foreach(i, ref v; data)
{
dg(v);
}
return 0;
}
void free()
{
if (dynamicStorage.length)
Delete(dynamicStorage);
numChunks = 0;
pos = 0;
}
}
void reallocateArray(T)(ref T[] buffer, size_t len)
{
T[] buffer2 = New!(T[])(len);
for(uint i = 0; i < buffer2.length; i++)
if (i < buffer.length)
buffer2[i] = buffer[i];
Delete(buffer);
buffer = buffer2;
}

View File

@ -1,70 +0,0 @@
/*
Copyright (c) 2015 Timur Gafarov
Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
// dimage is actually stripped out part of dlib - just to support reading PNG and JPEG
module dimage.bitio; //dlib.core.bitio
/*
* Bit-level manipulations
*/
enum Endian
{
Little,
Big
}
T hiNibble(T)(T b)
{
return ((b >> 4) & 0x0F);
}
T loNibble(T)(T b)
{
return (b & 0x0F);
}
T swapEndian16(T)(T n)
{
return cast(T)((n >> 8) | (n << 8));
}
T setBit(T)(T b, uint pos, bool state)
{
if (state)
return cast(T)(b | (1 << pos));
else
return cast(T)(b & ~(1 << pos));
}
bool getBit(T)(T b, uint pos)
{
return ((b & (1 << pos)) != 0);
}

View File

@ -1,43 +0,0 @@
/*
Copyright (c) 2011-2013 Timur Gafarov
Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
// dimage is actually stripped out part of dlib - just to support reading PNG and JPEG
//dlib.core.compound
module dimage.compound;
struct Compound(T...)
{
T tuple;
alias tuple this;
}
Compound!(T) compound(T...)(T args)
{
return Compound!(T)(args);
}

View File

@ -1,309 +0,0 @@
/*
Copyright (c) 2015 Timur Gafarov
Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
// dimage is actually stripped out part of dlib - just to support reading PNG and JPEG
module dimage.huffman;
import dimage.memory;
import dimage.bitio;
//import dlib.core.memory;
//import dlib.core.bitio;
struct HuffmanTreeNode
{
HuffmanTreeNode* parent;
HuffmanTreeNode* left;
HuffmanTreeNode* right;
ubyte ch;
uint freq;
bool blank = true;
this(
HuffmanTreeNode* leftNode,
HuffmanTreeNode* rightNode,
ubyte symbol,
uint frequency,
bool isBlank)
{
parent = null;
left = leftNode;
right = rightNode;
if (left !is null)
left.parent = &this;
if (right !is null)
right.parent = &this;
ch = symbol;
freq = frequency;
blank = isBlank;
}
bool isLeaf()
{
return (left is null && right is null);
}
void free()
{
if (left !is null)
{
left.free();
Delete(left);
}
if (right !is null)
{
right.free();
Delete(right);
}
}
/*
// TODO: implement this without GC
void getCodes(ref string[ubyte] table, string code = "")
{
if (isLeaf())
{
table[ch] = code;
}
else
{
if (left !is null)
left.getCodes(table, code ~ '0');
if (right !is null)
right.getCodes(table, code ~ '1');
}
}
void print(string indent = "")
{
writefln("%s<%s>%x", indent, freq, ch);
indent ~= " ";
if (left !is null)
left.print(indent);
if (right !is null)
right.print(indent);
}
*/
}
/*
// TODO: implement this without GC
HuffmanTreeNode* buildHuffmanTree(ubyte[] data)
{
// Count frequencies
uint[ubyte] freqs;
foreach(s; data)
{
if (s in freqs)
freqs[s] += 1;
else
freqs[s] = 1;
}
// Sort in descending order
ubyte[] symbols = freqs.keys;
sort!((a, b) => freqs[a] > freqs[b])(symbols);
// Create node list
auto nodeList = new HuffmanTreeNode*[symbols.length];
foreach(i, s; symbols)
nodeList[i] = new HuffmanTreeNode(null, null, s, freqs[s], false);
// Build tree
while (nodeList.length > 1)
{
// Pop two nodes with minimal frequencies
auto n1 = nodeList[$-1];
auto n2 = nodeList[$-2];
nodeList.popBack;
nodeList.popBack;
// Insert a new parent node
uint fsum = n1.freq + n2.freq;
auto parent = new HuffmanTreeNode(n1, n2, 0, fsum, false);
nodeList ~= parent;
sort!((a, b) => a.freq > b.freq)(nodeList);
}
auto root = nodeList[0];
return root;
}
void packHuffmanTree(HuffmanTreeNode* node, BitWriter* bw)
{
if (node.isLeaf)
{
bw.writeBit(true);
bw.writeByte(node.ch);
}
else
{
bw.writeBit(false);
packHuffmanTree(node.left, bw);
packHuffmanTree(node.right, bw);
}
}
HuffmanTreeNode* unpackHuffmanTree(BitReader* br)
{
if (!br.end)
{
bool bit = br.readBit();
if (bit)
{
byte ch = br.readByte();
return new HuffmanTreeNode(null, null, ch, 0, false);
}
else
{
HuffmanTreeNode* left = unpackHuffmanTree(br);
HuffmanTreeNode* right = unpackHuffmanTree(br);
return new HuffmanTreeNode(left, right, 0, 0, false);
}
}
else return null;
}
ubyte[] encodeHuffman(ubyte[] data, out HuffmanTreeNode* tree)
{
// Build Huffman tree
tree = buildHuffmanTree(data);
// Generate binary codes
string[ubyte] huffTable;
tree.getCodes(huffTable);
// Encode data
string bitStr;
foreach(s; data)
bitStr ~= huffTable[s];
// Pack bits to byte array
uint octetsLen = 0;
ubyte lastBits = 0;
if (bitStr.length == 8)
{
octetsLen = 1;
}
else if (bitStr.length > 8)
{
octetsLen = cast(uint)bitStr.length / 8;
lastBits = cast(ubyte)(bitStr.length % 8);
if (lastBits != 0)
octetsLen++;
}
else
{
octetsLen = 1;
lastBits = cast(ubyte)(bitStr.length);
}
octetsLen++;
auto octets = new ubyte[octetsLen];
octets[0] = lastBits;
uint bitPos = 0;
uint bytePos = 1;
foreach(bit; bitStr)
{
bool state;
if (bit == '0')
state = false;
else
state = true;
octets[bytePos] = setBit(octets[bytePos], bitPos, state);
bitPos++;
if (bitPos == 8)
{
bitPos = 0;
bytePos++;
}
}
return octets;
}
ubyte[] decodeHuffman(ubyte[] data, HuffmanTreeNode* tree)
{
// Generate binary codes
string[ubyte] huffTable;
tree.getCodes(huffTable);
//Unpack bits from array
ubyte[] result;
bool appendNext = true;
string code = "";
ubyte lastBits = data[0];
foreach(i, b; data[1..$])
{
uint len;
if ((lastBits != 0) && (i == data.length-1))
len = lastBits;
else
len = 8;
foreach(bp; 0..len)
{
char bitChr = getBit(b, bp)? '1':'0';
if (appendNext)
{
code ~= bitChr;
foreach(key, val; huffTable)
{
if (code == val)
{
result ~= key;
appendNext = false;
break;
}
}
}
else
{
code = "";
code ~= bitChr;
appendNext = true;
}
}
}
return result;
}
*/

217
3rdparty/dimage/idct.d vendored
View File

@ -1,217 +0,0 @@
/*
Copyright (c) 2014 Timur Gafarov
Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
// dimage is actually stripped out part of dlib - just to support reading PNG and JPEG
module dimage.idct; //dlib.image.io.idct
import std.math;
/*
* Inverse discrete cosine transform (DCT) for 64x64 blocks
*/
enum blockSize = 64; // A DCT block is 8x8.
enum w1 = 2841; // 2048*sqrt(2)*cos(1*pi/16)
enum w2 = 2676; // 2048*sqrt(2)*cos(2*pi/16)
enum w3 = 2408; // 2048*sqrt(2)*cos(3*pi/16)
enum w5 = 1609; // 2048*sqrt(2)*cos(5*pi/16)
enum w6 = 1108; // 2048*sqrt(2)*cos(6*pi/16)
enum w7 = 565; // 2048*sqrt(2)*cos(7*pi/16)
enum w1pw7 = w1 + w7;
enum w1mw7 = w1 - w7;
enum w2pw6 = w2 + w6;
enum w2mw6 = w2 - w6;
enum w3pw5 = w3 + w5;
enum w3mw5 = w3 - w5;
enum r2 = 181; // 256/sqrt(2)
// idct performs a 2-D Inverse Discrete Cosine Transformation.
//
// The input coefficients should already have been multiplied by the
// appropriate quantization table. We use fixed-point computation, with the
// number of bits for the fractional component varying over the intermediate
// stages.
//
// For more on the actual algorithm, see Z. Wang, "Fast algorithms for the
// discrete W transform and for the discrete Fourier transform", IEEE Trans. on
// ASSP, Vol. ASSP- 32, pp. 803-816, Aug. 1984.
void idct64(int* src)
{
// Horizontal 1-D IDCT.
for (uint y = 0; y < 8; y++)
{
int y8 = y * 8;
// If all the AC components are zero, then the IDCT is trivial.
if (src[y8+1] == 0 && src[y8+2] == 0 && src[y8+3] == 0 &&
src[y8+4] == 0 && src[y8+5] == 0 && src[y8+6] == 0 && src[y8+7] == 0)
{
int dc = src[y8+0] << 3;
src[y8+0] = dc;
src[y8+1] = dc;
src[y8+2] = dc;
src[y8+3] = dc;
src[y8+4] = dc;
src[y8+5] = dc;
src[y8+6] = dc;
src[y8+7] = dc;
continue;
}
// Prescale.
int x0 = (src[y8+0] << 11) + 128;
int x1 = src[y8+4] << 11;
int x2 = src[y8+6];
int x3 = src[y8+2];
int x4 = src[y8+1];
int x5 = src[y8+7];
int x6 = src[y8+5];
int x7 = src[y8+3];
// Stage 1.
int x8 = w7 * (x4 + x5);
x4 = x8 + w1mw7*x4;
x5 = x8 - w1pw7*x5;
x8 = w3 * (x6 + x7);
x6 = x8 - w3mw5*x6;
x7 = x8 - w3pw5*x7;
// Stage 2.
x8 = x0 + x1;
x0 -= x1;
x1 = w6 * (x3 + x2);
x2 = x1 - w2pw6*x2;
x3 = x1 + w2mw6*x3;
x1 = x4 + x6;
x4 -= x6;
x6 = x5 + x7;
x5 -= x7;
// Stage 3.
x7 = x8 + x3;
x8 -= x3;
x3 = x0 + x2;
x0 -= x2;
x2 = (r2*(x4+x5) + 128) >> 8;
x4 = (r2*(x4-x5) + 128) >> 8;
// Stage 4.
src[y8+0] = (x7 + x1) >> 8;
src[y8+1] = (x3 + x2) >> 8;
src[y8+2] = (x0 + x4) >> 8;
src[y8+3] = (x8 + x6) >> 8;
src[y8+4] = (x8 - x6) >> 8;
src[y8+5] = (x0 - x4) >> 8;
src[y8+6] = (x3 - x2) >> 8;
src[y8+7] = (x7 - x1) >> 8;
}
// Vertical 1-D IDCT.
for (uint x = 0; x < 8; x++)
{
// Similar to the horizontal 1-D IDCT case, if all the AC components are zero, then the IDCT is trivial.
// However, after performing the horizontal 1-D IDCT, there are typically non-zero AC components, so
// we do not bother to check for the all-zero case.
// Prescale.
int y0 = (src[8*0+x] << 8) + 8192;
int y1 = src[8*4+x] << 8;
int y2 = src[8*6+x];
int y3 = src[8*2+x];
int y4 = src[8*1+x];
int y5 = src[8*7+x];
int y6 = src[8*5+x];
int y7 = src[8*3+x];
// Stage 1.
int y8 = w7*(y4+y5) + 4;
y4 = (y8 + w1mw7*y4) >> 3;
y5 = (y8 - w1pw7*y5) >> 3;
y8 = w3*(y6+y7) + 4;
y6 = (y8 - w3mw5*y6) >> 3;
y7 = (y8 - w3pw5*y7) >> 3;
// Stage 2.
y8 = y0 + y1;
y0 -= y1;
y1 = w6*(y3+y2) + 4;
y2 = (y1 - w2pw6*y2) >> 3;
y3 = (y1 + w2mw6*y3) >> 3;
y1 = y4 + y6;
y4 -= y6;
y6 = y5 + y7;
y5 -= y7;
// Stage 3.
y7 = y8 + y3;
y8 -= y3;
y3 = y0 + y2;
y0 -= y2;
y2 = (r2*(y4+y5) + 128) >> 8;
y4 = (r2*(y4-y5) + 128) >> 8;
// Stage 4.
src[8*0+x] = (y7 + y1) >> 14;
src[8*1+x] = (y3 + y2) >> 14;
src[8*2+x] = (y0 + y4) >> 14;
src[8*3+x] = (y8 + y6) >> 14;
src[8*4+x] = (y8 - y6) >> 14;
src[8*5+x] = (y0 - y4) >> 14;
src[8*6+x] = (y3 - y2) >> 14;
src[8*7+x] = (y7 - y1) >> 14;
}
}
/*
void idct(float* inMat, float* outMat)
{
uint i, j, u, v;
float s;
for (i = 0; i < 8; i++)
for (j = 0; j < 8; j++)
{
s = 0;
for (u = 0; u < 8; u++)
for (v = 0; v < 8; v++)
{
s += inMat[u * 8 + v]
* cos((2 * i + 1) * u * PI / 16.0f)
* cos((2 * j + 1) * v * PI / 16.0f)
* ((u == 0) ? 1 / sqrt(2.0f) : 1.0f)
* ((v == 0) ? 1 / sqrt(2.0f) : 1.0f);
}
outMat[i * 8 + j] = s / 4.0f;
}
}
*/

View File

@ -1,83 +0,0 @@
// dimage is actually stripped out part of dlib - just to support reading PNG and JPEG
module dimage.image;
//import dimage.color;
class ImageLoadException : Exception
{
this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable next = null)
{
super(msg, file, line, next);
}
}
class SuperImageFactory {
SuperImage createImage(int width, int height, int components, int bitsPerComponent) {
return new SuperImage(width, height, components, bitsPerComponent);
}
}
class SuperImage {
immutable int width;
immutable int height;
uint[] data;
immutable int channels;
immutable int bitDepth;
immutable int length;
void opIndexAssign(uint color, int x, int y) {
data[x + y * width] = color;
}
uint opIndex(int x, int y) {
return data[x + y * width];
}
this(int w, int h, int chan, int depth) {
width = w;
height = h;
channels = chan;
bitDepth = depth;
length = width * height;
data.length = width * height;
}
void free() {
data = null;
}
}
__gshared SuperImageFactory defaultImageFactory = new SuperImageFactory();
/*
* Byte operations
*/
version (BigEndian)
{
uint bigEndian(uint value) nothrow
{
return value;
}
uint networkByteOrder(uint value) nothrow
{
return value;
}
}
version (LittleEndian)
{
uint bigEndian(uint value) nothrow
{
return value << 24
| (value & 0x0000FF00) << 8
| (value & 0x00FF0000) >> 8
| value >> 24;
}
uint networkByteOrder(uint value) nothrow
{
return bigEndian(value);
}
}

1306
3rdparty/dimage/jpeg.d vendored

File diff suppressed because it is too large Load Diff

View File

@ -1,208 +0,0 @@
/*
Copyright (c) 2015 Timur Gafarov
Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
// dimage is actually stripped out part of dlib - just to support reading PNG and JPEG
module dimage.memory;//dlib.core.memory
import std.stdio;
import std.conv;
import std.traits;
import core.stdc.stdlib;
import core.exception: onOutOfMemoryError;
/*
* Tools for manual memory management
*/
//version = MemoryDebug;
private static size_t _allocatedMemory = 0;
version(MemoryDebug)
{
import std.datetime;
import std.algorithm;
struct AllocationRecord
{
string type;
size_t size;
ulong id;
bool deleted;
}
AllocationRecord[ulong] records;
ulong counter = 0;
void addRecord(void* p, string type, size_t size)
{
records[cast(ulong)p] = AllocationRecord(type, size, counter, false);
counter++;
//writefln("Allocated %s (%s bytes)", type, size);
}
void markDeleted(void* p)
{
ulong k = cast(ulong)p - psize;
//string type = records[k].type;
//size_t size = records[k].size;
records[k].deleted = true;
//writefln("Dellocated %s (%s bytes)", type, size);
}
void printMemoryLog()
{
writeln("----------------------------------------------------");
writeln(" Memory allocation log ");
writeln("----------------------------------------------------");
auto keys = records.keys;
sort!((a, b) => records[a].id < records[b].id)(keys);
foreach(k; keys)
{
AllocationRecord r = records[k];
if (r.deleted)
writefln(" %s - %s byte(s) at %X", r.type, r.size, k);
else
writefln("REMAINS: %s - %s byte(s) at %X", r.type, r.size, k);
}
writeln("----------------------------------------------------");
writefln("Total amount of allocated memory: %s", _allocatedMemory);
writeln("----------------------------------------------------");
}
}
else
{
void printMemoryLog() {}
}
size_t allocatedMemory()
{
return _allocatedMemory;
}
interface Freeable
{
void free();
}
enum psize = 8;
T allocate(T, A...) (A args) if (is(T == class))
{
enum size = __traits(classInstanceSize, T);
void* p = malloc(size+psize);
if (!p)
onOutOfMemoryError();
auto memory = p[psize..psize+size];
*cast(size_t*)p = size;
_allocatedMemory += size;
version(MemoryDebug)
{
addRecord(p, T.stringof, size);
}
auto res = emplace!(T, A)(memory, args);
return res;
}
T* allocate(T, A...) (A args) if (is(T == struct))
{
enum size = T.sizeof;
void* p = malloc(size+psize);
if (!p)
onOutOfMemoryError();
auto memory = p[psize..psize+size];
*cast(size_t*)p = size;
_allocatedMemory += size;
version(MemoryDebug)
{
addRecord(p, T.stringof, size);
}
return emplace!(T, A)(memory, args);
}
T allocate(T) (size_t length) if (isArray!T)
{
alias AT = ForeachType!T;
size_t size = length * AT.sizeof;
auto mem = malloc(size+psize);
if (!mem)
onOutOfMemoryError();
T arr = cast(T)mem[psize..psize+size];
foreach(ref v; arr)
v = v.init;
*cast(size_t*)mem = size;
_allocatedMemory += size;
version(MemoryDebug)
{
addRecord(mem, T.stringof, size);
}
return arr;
}
void deallocate(T)(ref T obj) if (isArray!T)
{
void* p = cast(void*)obj.ptr;
size_t size = *cast(size_t*)(p - psize);
free(p - psize);
_allocatedMemory -= size;
version(MemoryDebug)
{
markDeleted(p);
}
obj.length = 0;
}
void deallocate(T)(T obj) if (is(T == class) || is(T == interface))
{
Object o = cast(Object)obj;
void* p = cast(void*)o;
size_t size = *cast(size_t*)(p - psize);
destroy(obj);
free(p - psize);
_allocatedMemory -= size;
version(MemoryDebug)
{
markDeleted(p);
}
}
void deallocate(T)(T* obj)
{
void* p = cast(void*)obj;
size_t size = *cast(size_t*)(p - psize);
destroy(obj);
free(p - psize);
_allocatedMemory -= size;
version(MemoryDebug)
{
markDeleted(p);
}
}
alias allocate New;
alias deallocate Delete;

851
3rdparty/dimage/png.d vendored
View File

@ -1,851 +0,0 @@
/*
Copyright (c) 2011-2015 Timur Gafarov, Martin Cejp
Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
// dimage is actually stripped out part of dlib - just to support reading PNG and JPEG
module dimage.png; //dlib.image.io.png
private
{
import std.stdio;
import std.math;
import std.string;
import std.range;
import dimage.memory;
import dimage.stream;
import dimage.compound;
//import dlib.filesystem.local;
//import dlib.math.utils;
import dimage.zlib;
import dimage.image;
//import dlib.image.io.io;
//import dlib.core.memory;
//import dlib.core.stream;
//import dlib.core.compound;
//import dlib.filesystem.local;
//import dlib.math.utils;
//import dlib.coding.zlib;
//import dlib.image.image;
//import dlib.image.io.io;
}
// uncomment this to see debug messages:
//version = PNGDebug;
static const ubyte[8] PNGSignature = [137, 80, 78, 71, 13, 10, 26, 10];
static const ubyte[4] IHDR = ['I', 'H', 'D', 'R'];
static const ubyte[4] IEND = ['I', 'E', 'N', 'D'];
static const ubyte[4] IDAT = ['I', 'D', 'A', 'T'];
static const ubyte[4] PLTE = ['P', 'L', 'T', 'E'];
static const ubyte[4] tRNS = ['t', 'R', 'N', 'S'];
static const ubyte[4] bKGD = ['b', 'K', 'G', 'D'];
static const ubyte[4] tEXt = ['t', 'E', 'X', 't'];
static const ubyte[4] iTXt = ['i', 'T', 'X', 't'];
static const ubyte[4] zTXt = ['z', 'T', 'X', 't'];
enum ColorType: ubyte
{
Greyscale = 0, // allowed bit depths: 1, 2, 4, 8 and 16
RGB = 2, // allowed bit depths: 8 and 16
Palette = 3, // allowed bit depths: 1, 2, 4 and 8
GreyscaleAlpha = 4, // allowed bit depths: 8 and 16
RGBA = 6, // allowed bit depths: 8 and 16
Any = 7 // one of the above
}
enum FilterMethod: ubyte
{
None = 0,
Sub = 1,
Up = 2,
Average = 3,
Paeth = 4
}
struct PNGChunk
{
uint length;
ubyte[4] type;
ubyte[] data;
uint crc;
void free()
{
if (data.ptr)
Delete(data);
}
}
struct PNGHeader
{
union
{
struct
{
uint width;
uint height;
ubyte bitDepth;
ubyte colorType;
ubyte compressionMethod;
ubyte filterMethod;
ubyte interlaceMethod;
};
ubyte[13] bytes;
}
}
class PNGLoadException: ImageLoadException
{
this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable next = null)
{
super(msg, file, line, next);
}
}
/*
* Load PNG from file using local FileSystem.
* Causes GC allocation
*/
//SuperImage loadPNG(string filename)
//{
// InputStream input = openForInput(filename);
// auto img = loadPNG(input);
// input.close();
// return img;
//}
/*
* Save PNG to file using local FileSystem.
* Causes GC allocation
*/
//void savePNG(SuperImage img, string filename)
//{
// OutputStream output = openForOutput(filename);
// Compound!(bool, string) res =
// savePNG(img, output);
// output.close();
//
// if (!res[0])
// throw new PNGLoadException(res[1]);
//}
/*
* Load PNG from stream using default image factory.
* Causes GC allocation
*/
SuperImage loadPNG(InputStream istrm)
{
Compound!(SuperImage, string) res =
loadPNG(istrm, defaultImageFactory);
if (res[0] is null)
throw new PNGLoadException(res[1]);
else
return res[0];
}
/*
* Load PNG from stream using specified image factory.
* GC-free
*/
Compound!(SuperImage, string) loadPNG(
InputStream istrm,
SuperImageFactory imgFac)
{
SuperImage img = null;
Compound!(SuperImage, string) error(string errorMsg)
{
if (img)
{
img.free();
img = null;
}
return compound(img, errorMsg);
}
bool readChunk(PNGChunk* chunk)
{
if (!istrm.readBE!uint(&chunk.length)
|| !istrm.fillArray(chunk.type))
{
return false;
}
version(PNGDebug) writefln("Chunk length = %s", chunk.length);
version(PNGDebug) writefln("Chunk type = %s", cast(char[])chunk.type);
if (chunk.length > 0)
{
chunk.data = New!(ubyte[])(chunk.length);
if (!istrm.fillArray(chunk.data))
{
return false;
}
}
version(PNGDebug) writefln("Chunk data.length = %s", chunk.data.length);
if (!istrm.readBE!uint(&chunk.crc))
{
return false;
}
// TODO: reimplement CRC check with ranges instead of concatenation
uint calculatedCRC = crc32(chain(chunk.type[0..$], chunk.data));
version(PNGDebug)
{
writefln("Chunk CRC = %X", chunk.crc);
writefln("Calculated CRC = %X", calculatedCRC);
writeln("-------------------");
}
if (chunk.crc != calculatedCRC)
{
return false;
}
return true;
}
bool readHeader(PNGHeader* hdr, PNGChunk* chunk)
{
hdr.bytes[] = chunk.data[];
hdr.width = bigEndian(hdr.width);
hdr.height = bigEndian(hdr.height);
version(PNGDebug)
{
writefln("width = %s", hdr.width);
writefln("height = %s", hdr.height);
writefln("bitDepth = %s", hdr.bitDepth);
writefln("colorType = %s", hdr.colorType);
writefln("compressionMethod = %s", hdr.compressionMethod);
writefln("filterMethod = %s", hdr.filterMethod);
writefln("interlaceMethod = %s", hdr.interlaceMethod);
writeln("----------------");
}
return true;
}
ubyte[8] signatureBuffer;
if (!istrm.fillArray(signatureBuffer))
{
return error("loadPNG error: signature check failed");
}
version(PNGDebug)
{
writeln("----------------");
writeln("PNG Signature: ", signatureBuffer);
writeln("----------------");
}
PNGHeader hdr;
ZlibDecoder zlibDecoder;
ubyte[] palette;
ubyte[] transparency;
uint paletteSize = 0;
bool endChunk = false;
while (!endChunk && istrm.readable)
{
PNGChunk chunk;
bool res = readChunk(&chunk);
if (!res)
{
chunk.free();
return error("loadPNG error: failed to read chunk");
}
else
{
if (chunk.type == IEND)
{
endChunk = true;
chunk.free();
}
else if (chunk.type == IHDR)
{
if (chunk.data.length < hdr.bytes.length)
return error("loadPNG error: illegal header chunk");
readHeader(&hdr, &chunk);
chunk.free();
bool supportedIndexed =
(hdr.colorType == ColorType.Palette) &&
(hdr.bitDepth == 1 ||
hdr.bitDepth == 2 ||
hdr.bitDepth == 4 ||
hdr.bitDepth == 8);
if (hdr.bitDepth != 8 && hdr.bitDepth != 16 && !supportedIndexed)
return error("loadPNG error: unsupported bit depth");
if (hdr.compressionMethod != 0)
return error("loadPNG error: unsupported compression method");
if (hdr.filterMethod != 0)
return error("loadPNG error: unsupported filter method");
if (hdr.interlaceMethod != 0)
return error("loadPNG error: interlacing is not supported");
uint bufferLength = ((hdr.width * hdr.bitDepth + 7) / 8) * hdr.height + hdr.height;
ubyte[] buffer = New!(ubyte[])(bufferLength);
zlibDecoder = ZlibDecoder(buffer);
version(PNGDebug)
{
writefln("buffer.length = %s", bufferLength);
writeln("----------------");
}
}
else if (chunk.type == IDAT)
{
zlibDecoder.decode(chunk.data);
chunk.free();
}
else if (chunk.type == PLTE)
{
palette = chunk.data;
}
else if (chunk.type == tRNS)
{
transparency = chunk.data;
version(PNGDebug)
{
writeln("----------------");
writefln("transparency.length = %s", transparency.length);
writeln("----------------");
}
}
else
{
chunk.free();
}
}
}
// finalize decoder
version(PNGDebug) writefln("zlibDecoder.hasEnded = %s", zlibDecoder.hasEnded);
if (!zlibDecoder.hasEnded)
return error("loadPNG error: unexpected end of zlib stream");
ubyte[] buffer = zlibDecoder.buffer;
version(PNGDebug) writefln("buffer.length = %s", buffer.length);
bool transparencyPalette;
// create image
if (hdr.colorType == ColorType.Greyscale)
{
if (hdr.bitDepth == 8)
img = imgFac.createImage(hdr.width, hdr.height, 1, 8);
else if (hdr.bitDepth == 16)
img = imgFac.createImage(hdr.width, hdr.height, 1, 16);
}
else if (hdr.colorType == ColorType.GreyscaleAlpha)
{
if (hdr.bitDepth == 8)
img = imgFac.createImage(hdr.width, hdr.height, 2, 8);
else if (hdr.bitDepth == 16)
img = imgFac.createImage(hdr.width, hdr.height, 2, 16);
}
else if (hdr.colorType == ColorType.RGB)
{
if (hdr.bitDepth == 8)
img = imgFac.createImage(hdr.width, hdr.height, 3, 8);
else if (hdr.bitDepth == 16)
img = imgFac.createImage(hdr.width, hdr.height, 3, 16);
}
else if (hdr.colorType == ColorType.RGBA)
{
if (hdr.bitDepth == 8)
img = imgFac.createImage(hdr.width, hdr.height, 4, 8);
else if (hdr.bitDepth == 16)
img = imgFac.createImage(hdr.width, hdr.height, 4, 16);
}
else if (hdr.colorType == ColorType.Palette)
{
if (transparency.length > 0) {
img = imgFac.createImage(hdr.width, hdr.height, 4, 8);
transparencyPalette = true;
} else
img = imgFac.createImage(hdr.width, hdr.height, 3, 8);
}
else
return error("loadPNG error: unsupported color type");
version(PNGDebug)
{
writefln("img.width = %s", img.width);
writefln("img.height = %s", img.height);
writefln("img.bitDepth = %s", img.bitDepth);
writefln("img.channels = %s", img.channels);
writeln("----------------");
}
bool indexed = (hdr.colorType == ColorType.Palette);
// don't close the stream, just release our reference
istrm = null;
// apply filtering to the image data
ubyte[] buffer2;
string errorMsg;
if (!filter(&hdr, img.channels, indexed, buffer, buffer2, errorMsg))
{
return error(errorMsg);
}
Delete(buffer);
buffer = buffer2;
// if a palette is used, substitute target colors
if (indexed)
{
if (palette.length == 0)
return error("loadPNG error: palette chunk not found");
ubyte[] pdata = New!(ubyte[])(img.width * img.height * img.channels);
if (hdr.bitDepth == 8)
{
for (int i = 0; i < buffer.length; ++i)
{
ubyte b = buffer[i];
pdata[i * img.channels + 0] = palette[b * 3 + 0];
pdata[i * img.channels + 1] = palette[b * 3 + 1];
pdata[i * img.channels + 2] = palette[b * 3 + 2];
if (transparency.length > 0)
pdata[i * img.channels + 3] =
b < transparency.length ? transparency[b] : 0;
}
}
else // bit depths 1, 2, 4
{
int srcindex = 0;
int srcshift = 8 - hdr.bitDepth;
ubyte mask = cast(ubyte)((1 << hdr.bitDepth) - 1);
int sz = img.width * img.height;
for (int dstindex = 0; dstindex < sz; dstindex++)
{
auto b = ((buffer[srcindex] >> srcshift) & mask);
//assert(b * 3 + 2 < palette.length);
pdata[dstindex * img.channels + 0] = palette[b * 3 + 0];
pdata[dstindex * img.channels + 1] = palette[b * 3 + 1];
pdata[dstindex * img.channels + 2] = palette[b * 3 + 2];
if (transparency.length > 0)
pdata[dstindex * img.channels + 3] =
b < transparency.length ? transparency[b] : 0;
if (srcshift <= 0)
{
srcshift = 8 - hdr.bitDepth;
srcindex++;
}
else
{
srcshift -= hdr.bitDepth;
}
}
}
Delete(buffer);
buffer = pdata;
Delete(palette);
if (transparency.length > 0)
Delete(transparency);
}
//if (img.data.length != buffer.length)
// return error("loadPNG error: uncompressed data length mismatch");
//
//foreach(i, v; buffer)
// img.data[i] = v;
int bufindex = 0;
if (hdr.colorType == ColorType.Greyscale)
{
if (hdr.bitDepth == 8) {
//img = imgFac.createImage(hdr.width, hdr.height, 1, 8);
for (int i = 0; i < img.length; i++) {
img.data[i] = ((cast(uint)buffer[bufindex])<<16) | ((cast(uint)buffer[bufindex])<<8) | ((cast(uint)buffer[bufindex])<<0) | 0xFF000000;
bufindex += 1;
}
} else if (hdr.bitDepth == 16) {
//img = imgFac.createImage(hdr.width, hdr.height, 1, 16);
assert(false);
}
}
else if (hdr.colorType == ColorType.GreyscaleAlpha)
{
if (hdr.bitDepth == 8) {
//img = imgFac.createImage(hdr.width, hdr.height, 2, 8);
for (int i = 0; i < img.length; i++) {
img.data[i] = ((cast(uint)buffer[bufindex])<<16) | ((cast(uint)buffer[bufindex])<<8) | ((cast(uint)buffer[bufindex])<<0) | ((cast(uint)buffer[bufindex + 1])<<24);
bufindex += 2;
}
} else if (hdr.bitDepth == 16) {
//img = imgFac.createImage(hdr.width, hdr.height, 2, 16);
assert(false);
}
}
else if (hdr.colorType == ColorType.RGB)
{
if (hdr.bitDepth == 8) {
//img = imgFac.createImage(hdr.width, hdr.height, 3, 8);
for (int i = 0; i < img.length; i++) {
img.data[i] = ((cast(uint)buffer[bufindex])<<16) | ((cast(uint)buffer[bufindex + 1])<<8) | ((cast(uint)buffer[bufindex + 2])<<0) | 0xFF000000;
bufindex += 3;
}
} else if (hdr.bitDepth == 16) {
//img = imgFac.createImage(hdr.width, hdr.height, 3, 16);
assert(false);
}
}
else if (hdr.colorType == ColorType.RGBA)
{
if (hdr.bitDepth == 8) {
//img = imgFac.createImage(hdr.width, hdr.height, 4, 8);
for (int i = 0; i < img.length; i++) {
img.data[i] = ((cast(uint)buffer[bufindex])<<16) | ((cast(uint)buffer[bufindex + 1])<<8) | ((cast(uint)buffer[bufindex + 2])<<0) | ((cast(uint)buffer[bufindex + 3])<<24);
bufindex += 4;
}
} else if (hdr.bitDepth == 16) {
//img = imgFac.createImage(hdr.width, hdr.height, 4, 16);
assert(false);
}
}
else if (hdr.colorType == ColorType.Palette)
{
if (transparencyPalette) {
for (int i = 0; i < img.length; i++) {
img.data[i] = ((cast(uint)buffer[bufindex])<<16) | ((cast(uint)buffer[bufindex + 1])<<8) | ((cast(uint)buffer[bufindex + 2])<<0) | ((cast(uint)buffer[bufindex + 3])<<24);
bufindex += 4;
}
//img = imgFac.createImage(hdr.width, hdr.height, 4, 8);
} else {
//img = imgFac.createImage(hdr.width, hdr.height, 3, 8);
for (int i = 0; i < img.length; i++) {
img.data[i] = ((cast(uint)buffer[bufindex])<<16) | ((cast(uint)buffer[bufindex + 1])<<8) | ((cast(uint)buffer[bufindex + 2])<<0) | 0xFF000000;
bufindex += 3;
}
}
}
Delete(buffer);
return compound(img, "");
}
version (ENABLE_SAVE_PNG) {
/*
* Save PNG to stream.
* GC-free
*/
Compound!(bool, string) savePNG(SuperImage img, OutputStream output)
in
{
assert (img.data.length);
}
do
{
Compound!(bool, string) error(string errorMsg)
{
return compound(false, errorMsg);
}
if (img.bitDepth != 8)
return error("savePNG error: only 8-bit images are supported by encoder");
bool writeChunk(ubyte[4] chunkType, ubyte[] chunkData)
{
PNGChunk hdrChunk;
hdrChunk.length = cast(uint)chunkData.length;
hdrChunk.type = chunkType;
hdrChunk.data = chunkData;
hdrChunk.crc = crc32(chain(chunkType[0..$], hdrChunk.data));
if (!output.writeBE!uint(hdrChunk.length)
|| !output.writeArray(hdrChunk.type))
return false;
if (chunkData.length)
if (!output.writeArray(hdrChunk.data))
return false;
if (!output.writeBE!uint(hdrChunk.crc))
return false;
return true;
}
bool writeHeader()
{
PNGHeader hdr;
hdr.width = networkByteOrder(img.width);
hdr.height = networkByteOrder(img.height);
hdr.bitDepth = 8;
if (img.channels == 4)
hdr.colorType = ColorType.RGBA;
else if (img.channels == 3)
hdr.colorType = ColorType.RGB;
else if (img.channels == 2)
hdr.colorType = ColorType.GreyscaleAlpha;
else if (img.channels == 1)
hdr.colorType = ColorType.Greyscale;
hdr.compressionMethod = 0;
hdr.filterMethod = 0;
hdr.interlaceMethod = 0;
return writeChunk(IHDR, hdr.bytes);
}
output.writeArray(PNGSignature);
if (!writeHeader())
return error("savePNG error: write failed (disk full?)");
//TODO: filtering
ubyte[] raw = New!(ubyte[])(img.width * img.height * img.channels + img.height);
foreach(y; 0..img.height)
{
auto rowStart = y * (img.width * img.channels + 1);
raw[rowStart] = 0; // No filter
foreach(x; 0..img.width)
{
auto dataIndex = (y * img.width + x) * img.channels;
auto rawIndex = rowStart + 1 + x * img.channels;
foreach(ch; 0..img.channels)
raw[rawIndex + ch] = img.data[dataIndex + ch];
}
}
ubyte[] buffer = New!(ubyte[])(64 * 1024);
ZlibBufferedEncoder zlibEncoder = ZlibBufferedEncoder(buffer, raw);
while (!zlibEncoder.ended)
{
auto len = zlibEncoder.encode();
if (len > 0)
writeChunk(IDAT, zlibEncoder.buffer[0..len]);
}
writeChunk(IEND, []);
Delete(buffer);
Delete(raw);
return compound(true, "");
}
}
/*
* performs the paeth PNG filter from pixels values:
* a = back
* b = up
* c = up and back
*/
pure ubyte paeth(ubyte a, ubyte b, ubyte c)
{
int p = a + b - c;
int pa = abs(p - a);
int pb = abs(p - b);
int pc = abs(p - c);
if (pa <= pb && pa <= pc) return a;
else if (pb <= pc) return b;
else return c;
}
bool filter(PNGHeader* hdr,
uint channels,
bool indexed,
ubyte[] ibuffer,
out ubyte[] obuffer,
out string errorMsg)
{
uint dataSize = cast(uint)ibuffer.length;
uint scanlineSize;
uint calculatedSize;
if (indexed)
{
calculatedSize = hdr.width * hdr.height * hdr.bitDepth / 8 + hdr.height;
scanlineSize = hdr.width * hdr.bitDepth / 8 + 1;
}
else
{
calculatedSize = hdr.width * hdr.height * channels + hdr.height;
scanlineSize = hdr.width * channels + 1;
}
version(PNGDebug)
{
writefln("[filter] dataSize = %s", dataSize);
writefln("[filter] calculatedSize = %s", calculatedSize);
}
if (dataSize != calculatedSize)
{
errorMsg = "loadPNG error: image size and data mismatch";
return false;
}
obuffer = New!(ubyte[])(calculatedSize - hdr.height);
ubyte pback, pup, pupback, cbyte;
for (int i = 0; i < hdr.height; ++i)
{
pback = 0;
// get the first byte of a scanline
ubyte scanFilter = ibuffer[i * scanlineSize];
if (indexed)
{
// TODO: support filtering for indexed images
if (scanFilter != FilterMethod.None)
{
errorMsg = "loadPNG error: filtering is not supported for indexed images";
return false;
}
for (int j = 1; j < scanlineSize; ++j)
{
ubyte b = ibuffer[(i * scanlineSize) + j];
obuffer[(i * (scanlineSize-1) + j - 1)] = b;
}
continue;
}
for (int j = 0; j < hdr.width; ++j)
{
for (int k = 0; k < channels; ++k)
{
if (i == 0) pup = 0;
else pup = obuffer[((i-1) * hdr.width + j) * channels + k]; // (hdr.height-(i-1)-1)
if (j == 0) pback = 0;
else pback = obuffer[(i * hdr.width + j-1) * channels + k];
if (i == 0 || j == 0) pupback = 0;
else pupback = obuffer[((i-1) * hdr.width + j - 1) * channels + k];
// get the current byte from ibuffer
cbyte = ibuffer[i * (hdr.width * channels + 1) + j * channels + k + 1];
// filter, then set the current byte in data
switch (scanFilter)
{
case FilterMethod.None:
obuffer[(i * hdr.width + j) * channels + k] = cbyte;
break;
case FilterMethod.Sub:
obuffer[(i * hdr.width + j) * channels + k] = cast(ubyte)(cbyte + pback);
break;
case FilterMethod.Up:
obuffer[(i * hdr.width + j) * channels + k] = cast(ubyte)(cbyte + pup);
break;
case FilterMethod.Average:
obuffer[(i * hdr.width + j) * channels + k] = cast(ubyte)(cbyte + (pback + pup) / 2);
break;
case FilterMethod.Paeth:
obuffer[(i * hdr.width + j) * channels + k] = cast(ubyte)(cbyte + paeth(pback, pup, pupback));
break;
default:
errorMsg = format("loadPNG error: unknown scanline filter (%s)", scanFilter);
return false;
}
}
}
}
return true;
}
uint crc32(R)(R range, uint inCrc = 0) if (isInputRange!R)
{
uint[256] generateTable()
{
uint[256] table;
uint crc;
for (int i = 0; i < 256; i++)
{
crc = i;
for (int j = 0; j < 8; j++)
crc = crc & 1 ? (crc >> 1) ^ 0xEDB88320UL : crc >> 1;
table[i] = crc;
}
return table;
}
static const uint[256] table = generateTable();
uint crc;
crc = inCrc ^ 0xFFFFFFFF;
foreach(v; range)
crc = (crc >> 8) ^ table[(crc ^ v) & 0xFF];
return (crc ^ 0xFFFFFFFF);
}
static if (false) {
unittest
{
import std.base64;
InputStream png() {
string minimal =
"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAADklEQVR42mL4z8AAEGAAAwEBAGb9nyQAAAAASUVORK5CYII=";
ubyte[] bytes = Base64.decode(minimal);
return new ArrayStream(bytes, bytes.length);
}
SuperImage img = loadPNG(png());
assert(img.width == 1);
assert(img.height == 1);
assert(img.channels == 3);
assert(img.pixelSize == 3);
assert(img.data == [0xff, 0x00, 0x00]);
createDir("tests", false);
savePNG(img, "tests/minimal.png");
loadPNG("tests/minimal.png");
}
}

View File

@ -1,263 +0,0 @@
/*
Copyright (c) 2014 Martin Cejp
Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
// dimage is actually stripped out part of dlib - just to support reading PNG and JPEG
//dlib.core.stream
module dimage.stream;
import std.bitmanip;
import std.stdint;
import std.conv;
//import dlib.core.memory;
alias StreamPos = uint64_t;
alias StreamSize = uint64_t;
alias StreamOffset = int64_t;
class SeekException : Exception
{
this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable next = null)
{
super(msg, file, line, next);
}
}
/// Seekable
interface Seekable
{
// Won't throw on invalid position, may throw on a more serious error.
StreamPos getPosition() @property;
bool setPosition(StreamPos pos);
StreamSize size();
// Throw-on-error wrappers
final StreamPos position(StreamPos pos)
{
if (!setPosition(pos))
throw new SeekException("Cannot set Seekable position to " ~ pos.to!string);
return pos;
}
final StreamPos position()
{
return getPosition();
}
// TODO: Non-throwing version
final StreamPos seek(StreamOffset amount)
{
immutable StreamPos seekTo = getPosition() + amount;
if (!setPosition(seekTo))
throw new SeekException("Cannot set Seekable position to " ~ seekTo.to!string);
return seekTo;
}
}
/// Stream
interface Stream : Seekable
{
void close();
bool seekable();
}
interface InputStream : Stream
{
// Won't throw on EOF, may throw on a more serious error.
bool readable();
size_t readBytes(void* buffer, size_t count);
/// Read array.length elements into an pre-allocated array.
/// Returns: true if all elements were read, false otherwise
final bool fillArray(T)(T[] array)
{
immutable size_t len = array.length * T.sizeof;
return readBytes(array.ptr, len) == len;
}
/// Read an integer in little-endian encoding
final bool readLE(T)(T* value)
{
ubyte[T.sizeof] buffer;
if (readBytes(buffer.ptr, buffer.length) != buffer.length)
return false;
*value = littleEndianToNative!T(buffer);
return true;
}
/// Read an integer in big-endian encoding
final bool readBE(T)(T* value)
{
ubyte[T.sizeof] buffer;
if (readBytes(buffer.ptr, buffer.length) != buffer.length)
return false;
*value = bigEndianToNative!T(buffer);
return true;
}
}
interface OutputStream : Stream
{
// Won't throw on full disk, may throw on a more serious error.
void flush();
bool writeable();
size_t writeBytes(const void* buffer, size_t count);
/// Write array.length elements from array.
/// Returns: true if all elements were written, false otherwise
final bool writeArray(T)(const T[] array)
{
immutable size_t len = array.length * T.sizeof;
return writeBytes(array.ptr, len) == len;
}
/// Write a string as zero-terminated
/// Returns: true on success, false otherwise
final bool writeStringz(string text)
{
ubyte[1] zero = [0];
return writeBytes(text.ptr, text.length)
&& writeBytes(zero.ptr, zero.length);
}
/// Write an integer in little-endian encoding
final bool writeLE(T)(const T value)
{
ubyte[T.sizeof] buffer = nativeToLittleEndian!T(value);
return writeBytes(buffer.ptr, buffer.length) == buffer.length;
}
/// Write an integer in big-endian encoding
final bool writeBE(T)(const T value)
{
ubyte[T.sizeof] buffer = nativeToBigEndian!T(value);
return writeBytes(buffer.ptr, buffer.length) == buffer.length;
}
}
interface IOStream : InputStream, OutputStream
{
}
StreamSize copyFromTo(InputStream input, OutputStream output)
{
ubyte[0x1000] buffer;
StreamSize total = 0;
while (input.readable)
{
size_t have = input.readBytes(buffer.ptr, buffer.length);
if (have == 0)
break;
output.writeBytes(buffer.ptr, have);
total += have;
}
return total;
}
// TODO: Move this?
// TODO: Add OutputStream methods
class ArrayStream : InputStream {
import std.algorithm;
this() {
}
this(ubyte[] data, size_t size) {
assert(size_ <= data.length);
this.size_ = size;
this.data = data;
}
override void close() {
this.pos = 0;
this.size_ = 0;
this.data = null;
}
override bool readable() {
return pos < size_;
}
override size_t readBytes(void* buffer, size_t count) {
import core.stdc.string;
count = min(count, size_ - pos);
// whoops, memcpy out of nowhere, can we do better than that?
memcpy(buffer, data.ptr + pos, count);
pos += count;
return count;
}
override bool seekable() {
return true;
}
override StreamPos getPosition() {
return pos;
}
override bool setPosition(StreamPos pos) {
if (pos > size_)
return false;
this.pos = cast(size_t)pos;
return true;
}
override StreamSize size() {
return size;
}
//mixin ManualModeImpl;
//mixin FreeImpl;
private:
size_t pos = 0, size_ = 0;
ubyte[] data; // data.length is capacity
}

165
3rdparty/dimage/zlib.d vendored
View File

@ -1,165 +0,0 @@
/*
Copyright (c) 2011-2015 Timur Gafarov
Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
// dimage is actually stripped out part of dlib - just to support reading PNG and JPEG
module dimage.zlib; //dlib.coding.zlib
private
{
import etc.c.zlib;
import dimage.memory;
}
struct ZlibBufferedEncoder
{
z_stream zlibStream;
ubyte[] buffer;
ubyte[] input;
bool ended = true;
this(ubyte[] buf, ubyte[] inp)
{
buffer = buf;
input = inp;
zlibStream.next_out = buffer.ptr;
zlibStream.avail_out = cast(uint)buffer.length;
zlibStream.data_type = Z_BINARY;
zlibStream.zalloc = null;
zlibStream.zfree = null;
zlibStream.opaque = null;
zlibStream.next_in = inp.ptr;
zlibStream.avail_in = cast(uint)inp.length;
deflateInit(&zlibStream, Z_BEST_COMPRESSION);
ended = false;
}
size_t encode()
{
zlibStream.next_out = buffer.ptr;
zlibStream.avail_out = cast(uint)buffer.length;
zlibStream.total_out = 0;
while (zlibStream.avail_out > 0)
{
int msg = deflate(&zlibStream, Z_FINISH);
if (msg == Z_STREAM_END)
{
deflateEnd(&zlibStream);
ended = true;
return zlibStream.total_out;
}
else if (msg != Z_OK)
{
deflateEnd(&zlibStream);
return 0;
}
}
return zlibStream.total_out;
}
}
struct ZlibDecoder
{
z_stream zlibStream;
ubyte[] buffer;
int msg = 0;
bool isInitialized = false;
bool hasEnded = false;
this(ubyte[] buf)
{
buffer = buf;
zlibStream.next_out = buffer.ptr;
zlibStream.avail_out = cast(uint)buffer.length;
zlibStream.data_type = Z_BINARY;
}
bool decode(ubyte[] input)
{
zlibStream.next_in = input.ptr;
zlibStream.avail_in = cast(uint)input.length;
if (!isInitialized)
{
isInitialized = true;
msg = inflateInit(&zlibStream);
if (msg)
{
inflateEnd(&zlibStream);
return false;
}
}
while (zlibStream.avail_in)
{
msg = inflate(&zlibStream, Z_NO_FLUSH);
if (msg == Z_STREAM_END)
{
inflateEnd(&zlibStream);
hasEnded = true;
reallocateBuffer(zlibStream.total_out);
return true;
}
else if (msg != Z_OK)
{
inflateEnd(&zlibStream);
return false;
}
else if (zlibStream.avail_out == 0)
{
reallocateBuffer(buffer.length * 2);
zlibStream.next_out = &buffer[buffer.length / 2];
zlibStream.avail_out = cast(uint)(buffer.length / 2);
}
}
return true;
}
void reallocateBuffer(size_t len)
{
ubyte[] buffer2 = New!(ubyte[])(len);
for(uint i = 0; i < buffer2.length; i++)
if (i < buffer.length)
buffer2[i] = buffer[i];
Delete(buffer);
buffer = buffer2;
}
void free()
{
Delete(buffer);
}
}

View File

@ -151,9 +151,8 @@ Third party components used
* `binbc-opengl` - for OpenGL support
* `bindbc-freetype` + FreeType library support under linux and optionally under Windows.
* `bindbc-sdl` + SDL2 for cross platform support
* WindowsAPI bindings from http://www.dsource.org/projects/bindings/wiki/WindowsApi (patched)
* X11 binding when SDL2 is not used
* PNG and JPEG reading code is based on dlib sources
* `arsd-official` For image reading and XML parsing
Hello World

View File

@ -34,7 +34,8 @@
"dependencies": {
"inilike": "~>1.2.2",
"icontheme": "~>1.2.3",
"arsd-official:dom": "~>10.9.8"
"arsd-official:dom": "~>10.9.10",
"arsd-official:image_files": "~>10.9.10"
},
"subPackages": [

View File

@ -23,25 +23,7 @@ module dlangui.graphics.images;
public import dlangui.core.config;
static if (BACKEND_GUI):
//version = USE_DEIMAGE;
//version = USE_DLIBIMAGE;
version = USE_DIMAGE;
version (USE_DEIMAGE) {
import devisualization.image;
import devisualization.image.png;
} else version (USE_DIMAGE) {
//import dimage.io;
import dimage.image;
import dimage.png;
import dimage.jpeg;
} else version (USE_DLIBIMAGE) {
import dlib.image.io.io;
import dlib.image.image;
import dlib.image.io.png;
import dlib.image.io.jpeg;
version = ENABLE_DLIBIMAGE_JPEG;
}
import arsd.image;
import dlangui.core.logger;
import dlangui.core.types;
@ -82,138 +64,16 @@ ColorDrawBuf loadImage(immutable ubyte[] data, string filename) {
}
}
version (USE_DEIMAGE) {
try {
Image image = imageFromData(extension(filename)[1 ..$], cast(ubyte[])data); //imageFromFile(filename);
int w = cast(int)image.width;
int h = cast(int)image.height;
ColorDrawBuf buf = new ColorDrawBuf(w, h);
Color_RGBA[] pixels = image.rgba.allPixels;
int index = 0;
foreach(y; 0 .. h) {
uint * dstLine = buf.scanLine(y);
foreach(x; 0 .. w) {
Color_RGBA * pixel = &pixels[index + x];
dstLine[x] = makeRGBA(pixel.r_ubyte, pixel.g_ubyte, pixel.b_ubyte, pixel.a_ubyte);
}
index += w;
}
//destroy(image);
return buf;
} catch (NotAnImageException e) {
Log.e("Failed to load image from file ", filename, " using de_image");
Log.e(to!string(e));
return null;
}
} else version (USE_DLIBIMAGE) {
static import dlib.core.stream;
try {
version (ENABLE_DLIBIMAGE_JPEG) {
} else {
// temporary disabling of JPEG support - until DLIB included it
if (filename.endsWith(".jpeg") || filename.endsWith(".jpg") || filename.endsWith(".JPG") || filename.endsWith(".JPEG"))
return null;
}
SuperImage image = null;
dlib.core.stream.ArrayStream dlibstream = new dlib.core.stream.ArrayStream(cast(ubyte[])data, data.length);
switch(filename.extension)
{
case ".jpg", ".JPG", ".jpeg":
image = dlib.image.io.jpeg.loadJPEG(dlibstream);
break;
case ".png", ".PNG":
image = dlib.image.io.png.loadPNG(dlibstream);
break;
default:
break;
}
//SuperImage image = dlib.image.io.io.loadImage(filename);
if (!image)
return null;
ColorDrawBuf buf = importImage(image);
destroy(image);
return buf;
} catch (Exception e) {
Log.e("Failed to load image from file ", filename, " using dlib image");
Log.e(to!string(e));
return null;
}
} else version (USE_DIMAGE) {
static import dimage.stream;
try {
SuperImage image = null;
dimage.stream.ArrayStream dlibstream = new dimage.stream.ArrayStream(cast(ubyte[])data, data.length);
switch(filename.extension)
{
case ".jpg", ".JPG", ".jpeg":
image = dimage.jpeg.loadJPEG(dlibstream);
break;
case ".png", ".PNG":
image = dimage.png.loadPNG(dlibstream);
break;
default:
break;
}
//SuperImage image = dlib.image.io.io.loadImage(filename);
if (!image)
return null;
ColorDrawBuf buf = importImage(image);
destroy(image);
return buf;
} catch (Exception e) {
Log.e("Failed to load image from file ", filename, " using dlib image");
Log.e(to!string(e));
return null;
}
} else {
try {
std.stream.File f = new std.stream.File(filename);
scope(exit) { f.close(); }
return loadImage(f);
} catch (Exception e) {
Log.e("exception while loading image from file ", filename);
Log.e(to!string(e));
return null;
auto image = loadImageFromMemory(data);
ColorDrawBuf buf = new ColorDrawBuf(image.width, image.height);
for(int j = 0; j < buf.height; j++)
{
auto scanLine = buf.scanLine(j);
for(int i = 0; i < buf.width; i++)
{
auto color = image.getPixel(i, j);
scanLine[i] = makeRGBA(color.r, color.g, color.b, 255 - color.a);
}
}
return buf;
}
version (USE_DLIBIMAGE) {
ColorDrawBuf importImage(SuperImage image) {
int w = image.width;
int h = image.height;
ColorDrawBuf buf = new ColorDrawBuf(w, h);
foreach(y; 0 .. h) {
uint * dstLine = buf.scanLine(y);
foreach(x; 0 .. w) {
auto pixel = image[x, y].convert(8);
dstLine[x] = makeRGBA(pixel.r, pixel.g, pixel.b, 255 - pixel.a);
}
}
return buf;
}
}
version (USE_DIMAGE) {
ColorDrawBuf importImage(SuperImage image) {
int w = image.width;
int h = image.height;
ColorDrawBuf buf = new ColorDrawBuf(w, h);
foreach(y; 0 .. h) {
uint * dstLine = buf.scanLine(y);
foreach(x; 0 .. w) {
uint pixel = image[x, y];
dstLine[x] = pixel ^ 0xFF000000;
}
}
return buf;
}
}
class ImageDecodingException : Exception {
this(string msg) {
super(msg);
}
}