mirror of https://github.com/adamdruppe/arsd.git
apng starting code
This commit is contained in:
parent
68e67279f2
commit
6e55085a10
201
png.d
201
png.d
|
@ -138,88 +138,9 @@ MemoryImage imageFromPng(PNG* png) {
|
||||||
foreach(line; file.rawDatastreamByChunk()) {
|
foreach(line; file.rawDatastreamByChunk()) {
|
||||||
auto filter = line[0];
|
auto filter = line[0];
|
||||||
auto data = unfilter(filter, line[1 .. $], previousLine, bpp);
|
auto data = unfilter(filter, line[1 .. $], previousLine, bpp);
|
||||||
ubyte consumeOne() {
|
|
||||||
ubyte ret = data[0];
|
|
||||||
data = data[1 .. $];
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
previousLine = data;
|
previousLine = data;
|
||||||
import std.conv;
|
|
||||||
|
|
||||||
loop: for(int pixel = 0; pixel < h.width; pixel++)
|
convertPngData(h.type, h.depth, data, h.width, idata, idataIdx);
|
||||||
switch(h.type) {
|
|
||||||
case 0: // greyscale
|
|
||||||
case 4: // greyscale with alpha
|
|
||||||
auto value = consumeOne();
|
|
||||||
idata[idataIdx++] = value;
|
|
||||||
idata[idataIdx++] = value;
|
|
||||||
idata[idataIdx++] = value;
|
|
||||||
idata[idataIdx++] = (h.type == 4) ? consumeOne() : 255;
|
|
||||||
break;
|
|
||||||
case 3: // indexed
|
|
||||||
auto b = consumeOne();
|
|
||||||
switch(h.depth) {
|
|
||||||
case 1:
|
|
||||||
idata[idataIdx++] = (b >> 7) & 0x01;
|
|
||||||
pixel++; if(pixel == h.width) break loop;
|
|
||||||
idata[idataIdx++] = (b >> 6) & 0x01;
|
|
||||||
pixel++; if(pixel == h.width) break loop;
|
|
||||||
idata[idataIdx++] = (b >> 5) & 0x01;
|
|
||||||
pixel++; if(pixel == h.width) break loop;
|
|
||||||
idata[idataIdx++] = (b >> 4) & 0x01;
|
|
||||||
pixel++; if(pixel == h.width) break loop;
|
|
||||||
idata[idataIdx++] = (b >> 3) & 0x01;
|
|
||||||
pixel++; if(pixel == h.width) break loop;
|
|
||||||
idata[idataIdx++] = (b >> 2) & 0x01;
|
|
||||||
pixel++; if(pixel == h.width) break loop;
|
|
||||||
idata[idataIdx++] = (b >> 1) & 0x01;
|
|
||||||
pixel++; if(pixel == h.width) break loop;
|
|
||||||
idata[idataIdx++] = b & 0x01;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
idata[idataIdx++] = (b >> 6) & 0x03;
|
|
||||||
pixel++; if(pixel == h.width) break loop;
|
|
||||||
idata[idataIdx++] = (b >> 4) & 0x03;
|
|
||||||
pixel++; if(pixel == h.width) break loop;
|
|
||||||
idata[idataIdx++] = (b >> 2) & 0x03;
|
|
||||||
pixel++; if(pixel == h.width) break loop;
|
|
||||||
idata[idataIdx++] = b & 0x03;
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
idata[idataIdx++] = (b >> 4) & 0x0f;
|
|
||||||
pixel++; if(pixel == h.width) break loop;
|
|
||||||
idata[idataIdx++] = b & 0x0f;
|
|
||||||
break;
|
|
||||||
case 8:
|
|
||||||
idata[idataIdx++] = b;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
assert(0, "bit depth not implemented");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 2: // truecolor
|
|
||||||
case 6: // true with alpha
|
|
||||||
if(h.depth == 8) {
|
|
||||||
idata[idataIdx++] = consumeOne();
|
|
||||||
idata[idataIdx++] = consumeOne();
|
|
||||||
idata[idataIdx++] = consumeOne();
|
|
||||||
idata[idataIdx++] = (h.type == 6) ? consumeOne() : 255;
|
|
||||||
} else if(h.depth == 16) {
|
|
||||||
idata[idataIdx++] = consumeOne();
|
|
||||||
consumeOne();
|
|
||||||
idata[idataIdx++] = consumeOne();
|
|
||||||
consumeOne();
|
|
||||||
idata[idataIdx++] = consumeOne();
|
|
||||||
consumeOne();
|
|
||||||
idata[idataIdx++] = (h.type == 6) ? consumeOne() : 255;
|
|
||||||
if(h.type == 6)
|
|
||||||
consumeOne();
|
|
||||||
|
|
||||||
} else assert(0, "unsupported truecolor bit depth " ~ to!string(h.depth));
|
|
||||||
break;
|
|
||||||
default: assert(0);
|
|
||||||
}
|
|
||||||
assert(data.length == 0, "not all consumed, wtf " ~ to!string(h));
|
|
||||||
}
|
}
|
||||||
assert(idataIdx == idata.length, "not all filled, wtf");
|
assert(idataIdx == idata.length, "not all filled, wtf");
|
||||||
|
|
||||||
|
@ -228,6 +149,91 @@ MemoryImage imageFromPng(PNG* png) {
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// idata needs to be already sized for the image! width * height if indexed, width*height*4 if not.
|
||||||
|
void convertPngData(ubyte type, ubyte depth, const(ubyte)[] data, int width, ubyte[] idata, ref int idataIdx) {
|
||||||
|
ubyte consumeOne() {
|
||||||
|
ubyte ret = data[0];
|
||||||
|
data = data[1 .. $];
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
import std.conv;
|
||||||
|
|
||||||
|
loop: for(int pixel = 0; pixel < width; pixel++)
|
||||||
|
switch(type) {
|
||||||
|
case 0: // greyscale
|
||||||
|
case 4: // greyscale with alpha
|
||||||
|
auto value = consumeOne();
|
||||||
|
idata[idataIdx++] = value;
|
||||||
|
idata[idataIdx++] = value;
|
||||||
|
idata[idataIdx++] = value;
|
||||||
|
idata[idataIdx++] = (type == 4) ? consumeOne() : 255;
|
||||||
|
break;
|
||||||
|
case 3: // indexed
|
||||||
|
auto b = consumeOne();
|
||||||
|
switch(depth) {
|
||||||
|
case 1:
|
||||||
|
idata[idataIdx++] = (b >> 7) & 0x01;
|
||||||
|
pixel++; if(pixel == width) break loop;
|
||||||
|
idata[idataIdx++] = (b >> 6) & 0x01;
|
||||||
|
pixel++; if(pixel == width) break loop;
|
||||||
|
idata[idataIdx++] = (b >> 5) & 0x01;
|
||||||
|
pixel++; if(pixel == width) break loop;
|
||||||
|
idata[idataIdx++] = (b >> 4) & 0x01;
|
||||||
|
pixel++; if(pixel == width) break loop;
|
||||||
|
idata[idataIdx++] = (b >> 3) & 0x01;
|
||||||
|
pixel++; if(pixel == width) break loop;
|
||||||
|
idata[idataIdx++] = (b >> 2) & 0x01;
|
||||||
|
pixel++; if(pixel == width) break loop;
|
||||||
|
idata[idataIdx++] = (b >> 1) & 0x01;
|
||||||
|
pixel++; if(pixel == width) break loop;
|
||||||
|
idata[idataIdx++] = b & 0x01;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
idata[idataIdx++] = (b >> 6) & 0x03;
|
||||||
|
pixel++; if(pixel == width) break loop;
|
||||||
|
idata[idataIdx++] = (b >> 4) & 0x03;
|
||||||
|
pixel++; if(pixel == width) break loop;
|
||||||
|
idata[idataIdx++] = (b >> 2) & 0x03;
|
||||||
|
pixel++; if(pixel == width) break loop;
|
||||||
|
idata[idataIdx++] = b & 0x03;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
idata[idataIdx++] = (b >> 4) & 0x0f;
|
||||||
|
pixel++; if(pixel == width) break loop;
|
||||||
|
idata[idataIdx++] = b & 0x0f;
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
idata[idataIdx++] = b;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert(0, "bit depth not implemented");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 2: // truecolor
|
||||||
|
case 6: // true with alpha
|
||||||
|
if(depth == 8) {
|
||||||
|
idata[idataIdx++] = consumeOne();
|
||||||
|
idata[idataIdx++] = consumeOne();
|
||||||
|
idata[idataIdx++] = consumeOne();
|
||||||
|
idata[idataIdx++] = (type == 6) ? consumeOne() : 255;
|
||||||
|
} else if(depth == 16) {
|
||||||
|
idata[idataIdx++] = consumeOne();
|
||||||
|
consumeOne();
|
||||||
|
idata[idataIdx++] = consumeOne();
|
||||||
|
consumeOne();
|
||||||
|
idata[idataIdx++] = consumeOne();
|
||||||
|
consumeOne();
|
||||||
|
idata[idataIdx++] = (type == 6) ? consumeOne() : 255;
|
||||||
|
if(type == 6)
|
||||||
|
consumeOne();
|
||||||
|
|
||||||
|
} else assert(0, "unsupported truecolor bit depth " ~ to!string(depth));
|
||||||
|
break;
|
||||||
|
default: assert(0);
|
||||||
|
}
|
||||||
|
assert(data.length == 0, "not all consumed, wtf ");// ~ to!string(h));
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
struct PngHeader {
|
struct PngHeader {
|
||||||
uint width;
|
uint width;
|
||||||
|
@ -1467,29 +1473,32 @@ struct LazyPngFile(LazyPngChunksProvider)
|
||||||
return .bytesPerPixel(header);
|
return .bytesPerPixel(header);
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: doesn't handle interlacing... I think
|
|
||||||
int bytesPerLine() {
|
int bytesPerLine() {
|
||||||
immutable bitsPerChannel = header.depth;
|
return .bytesPerLineOfPng(header.depth, header.type, header.width);
|
||||||
|
|
||||||
int bitsPerPixel = bitsPerChannel;
|
|
||||||
if(header.type & 2 && !(header.type & 1)) // in color, but no palette
|
|
||||||
bitsPerPixel *= 3;
|
|
||||||
if(header.type & 4) // has alpha channel
|
|
||||||
bitsPerPixel += bitsPerChannel;
|
|
||||||
|
|
||||||
|
|
||||||
immutable int sizeInBits = header.width * bitsPerPixel;
|
|
||||||
|
|
||||||
// need to round up to the nearest byte
|
|
||||||
int sizeInBytes = (sizeInBits + 7) / 8;
|
|
||||||
|
|
||||||
return sizeInBytes + 1; // the +1 is for the filter byte that precedes all lines
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PngHeader header;
|
PngHeader header;
|
||||||
Color[] palette;
|
Color[] palette;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: doesn't handle interlacing... I think
|
||||||
|
@nogc @safe pure nothrow
|
||||||
|
int bytesPerLineOfPng(ubyte depth, ubyte type, uint width) {
|
||||||
|
immutable bitsPerChannel = depth;
|
||||||
|
|
||||||
|
int bitsPerPixel = bitsPerChannel;
|
||||||
|
if(type & 2 && !(type & 1)) // in color, but no palette
|
||||||
|
bitsPerPixel *= 3;
|
||||||
|
if(type & 4) // has alpha channel
|
||||||
|
bitsPerPixel += bitsPerChannel;
|
||||||
|
|
||||||
|
immutable int sizeInBits = width * bitsPerPixel;
|
||||||
|
|
||||||
|
// need to round up to the nearest byte
|
||||||
|
int sizeInBytes = (sizeInBits + 7) / 8;
|
||||||
|
|
||||||
|
return sizeInBytes + 1; // the +1 is for the filter byte that precedes all lines
|
||||||
|
}
|
||||||
|
|
||||||
/**************************************************
|
/**************************************************
|
||||||
* Buffered input range - generic, non-image code
|
* Buffered input range - generic, non-image code
|
||||||
|
|
|
@ -45,7 +45,7 @@ module arsd.simpleaudio;
|
||||||
enum BUFFER_SIZE_FRAMES = 1024;//512;//2048;
|
enum BUFFER_SIZE_FRAMES = 1024;//512;//2048;
|
||||||
enum BUFFER_SIZE_SHORT = BUFFER_SIZE_FRAMES * 2;
|
enum BUFFER_SIZE_SHORT = BUFFER_SIZE_FRAMES * 2;
|
||||||
|
|
||||||
///
|
/// A reasonable default volume for an individual sample. It doesn't need to be large; in fact it needs to not be large so mixing doesn't clip too much.
|
||||||
enum DEFAULT_VOLUME = 20;
|
enum DEFAULT_VOLUME = 20;
|
||||||
|
|
||||||
version(Demo)
|
version(Demo)
|
||||||
|
|
Loading…
Reference in New Issue