Fix the Windows icon generation, add Bitmap encoding support, break JPG/PNG support into separate lime.graphics.format.* class files
This commit is contained in:
@@ -6,6 +6,9 @@ import haxe.io.Bytes;
|
||||
import haxe.io.BytesInput;
|
||||
import haxe.io.BytesOutput;
|
||||
import lime.app.Application;
|
||||
import lime.graphics.format.BMP;
|
||||
import lime.graphics.format.JPEG;
|
||||
import lime.graphics.format.PNG;
|
||||
import lime.graphics.utils.ImageCanvasUtil;
|
||||
import lime.graphics.utils.ImageDataUtil;
|
||||
import lime.math.ColorMatrix;
|
||||
@@ -292,54 +295,15 @@ class Image {
|
||||
|
||||
case "png":
|
||||
|
||||
#if java
|
||||
|
||||
#elseif (sys && (!disable_cffi || !format))
|
||||
|
||||
return lime_image_encode (buffer, 0, quality);
|
||||
|
||||
#elseif !js
|
||||
|
||||
try {
|
||||
|
||||
var bytes = Bytes.alloc (width * height * 4 + height);
|
||||
var sourceBytes = buffer.data.getByteBuffer ();
|
||||
var sourceIndex:Int, index:Int;
|
||||
|
||||
for (y in 0...height) {
|
||||
|
||||
sourceIndex = y * width * 4;
|
||||
index = y * width * 4 + y;
|
||||
|
||||
bytes.set (index, 0);
|
||||
bytes.blit (index + 1, sourceBytes, sourceIndex, width * 4);
|
||||
|
||||
}
|
||||
|
||||
var data = new List ();
|
||||
data.add (CHeader ({ width: width, height: height, colbits: 8, color: ColTrue (true), interlaced: false }));
|
||||
data.add (CData (Deflate.run (bytes)));
|
||||
data.add (CEnd);
|
||||
|
||||
var output = new BytesOutput ();
|
||||
var png = new Writer (output);
|
||||
png.write (data);
|
||||
|
||||
return ByteArray.fromBytes (output.getBytes ());
|
||||
|
||||
} catch (e:Dynamic) {}
|
||||
|
||||
#end
|
||||
return PNG.encode (this);
|
||||
|
||||
case "jpg", "jpeg":
|
||||
|
||||
#if java
|
||||
return JPEG.encode (this, quality);
|
||||
|
||||
case "bmp":
|
||||
|
||||
#elseif (sys && (!disable_cffi || !format))
|
||||
|
||||
return lime_image_encode (buffer, 1, quality);
|
||||
|
||||
#end
|
||||
return BMP.encode (this);
|
||||
|
||||
default:
|
||||
|
||||
|
||||
185
lime/graphics/format/BMP.hx
Normal file
185
lime/graphics/format/BMP.hx
Normal file
@@ -0,0 +1,185 @@
|
||||
package lime.graphics.format;
|
||||
|
||||
|
||||
import lime.graphics.Image;
|
||||
import lime.math.Rectangle;
|
||||
import lime.utils.ByteArray;
|
||||
|
||||
|
||||
class BMP {
|
||||
|
||||
|
||||
public static function encode (image:Image, type:BMPType = null):ByteArray {
|
||||
|
||||
if (type == null) {
|
||||
|
||||
type = RGB;
|
||||
|
||||
}
|
||||
|
||||
var fileHeaderLength = 14;
|
||||
var infoHeaderLength = 40;
|
||||
var pixelValuesLength = (image.width * image.height * 4);
|
||||
|
||||
switch (type) {
|
||||
|
||||
case BITFIELD:
|
||||
|
||||
infoHeaderLength = 108;
|
||||
|
||||
case ICO:
|
||||
|
||||
fileHeaderLength = 0;
|
||||
pixelValuesLength += image.width * image.height;
|
||||
|
||||
default:
|
||||
|
||||
}
|
||||
|
||||
var data = new ByteArray (fileHeaderLength + infoHeaderLength + pixelValuesLength);
|
||||
data.bigEndian = false;
|
||||
|
||||
if (fileHeaderLength > 0) {
|
||||
|
||||
data.writeByte (0x42);
|
||||
data.writeByte (0x4D);
|
||||
data.writeInt (data.length);
|
||||
data.writeInt (0);
|
||||
data.writeInt (fileHeaderLength + infoHeaderLength);
|
||||
|
||||
}
|
||||
|
||||
data.writeInt (infoHeaderLength);
|
||||
data.writeInt (image.width);
|
||||
|
||||
if (type == ICO) {
|
||||
|
||||
data.writeInt (image.height * 2);
|
||||
|
||||
} else {
|
||||
|
||||
data.writeInt (image.height);
|
||||
|
||||
}
|
||||
|
||||
data.writeShort (1);
|
||||
data.writeShort (32);
|
||||
|
||||
switch (type) {
|
||||
|
||||
case BITFIELD: data.writeInt (3);
|
||||
default: data.writeInt (0);
|
||||
|
||||
}
|
||||
|
||||
data.writeInt (pixelValuesLength);
|
||||
data.writeInt (0x2e30);
|
||||
data.writeInt (0x2e30);
|
||||
data.writeInt (0);
|
||||
data.writeInt (0);
|
||||
|
||||
if (type == BITFIELD) {
|
||||
|
||||
data.writeInt (0x00FF0000);
|
||||
data.writeInt (0x0000FF00);
|
||||
data.writeInt (0x000000FF);
|
||||
data.writeInt (0xFF000000);
|
||||
data.writeByte (0x20);
|
||||
data.writeByte (0x6E);
|
||||
data.writeByte (0x69);
|
||||
data.writeByte (0x57);
|
||||
data.writeInt (0);
|
||||
data.writeInt (0);
|
||||
data.writeInt (0);
|
||||
data.writeInt (0);
|
||||
data.writeInt (0);
|
||||
data.writeInt (0);
|
||||
data.writeInt (0);
|
||||
data.writeInt (0);
|
||||
data.writeInt (0);
|
||||
data.writeInt (0);
|
||||
data.writeInt (0);
|
||||
data.writeInt (0);
|
||||
|
||||
}
|
||||
|
||||
var pixels = image.getPixels (new Rectangle (0, 0, image.width, image.height));
|
||||
var a, r, g, b;
|
||||
|
||||
if (type != ICO) {
|
||||
|
||||
for (y in 0...image.height) {
|
||||
|
||||
pixels.position = (image.height - 1 - y) * 4 * image.width;
|
||||
|
||||
for (x in 0...image.width) {
|
||||
|
||||
a = pixels.readByte ();
|
||||
r = pixels.readByte ();
|
||||
g = pixels.readByte ();
|
||||
b = pixels.readByte ();
|
||||
|
||||
data.writeByte (b);
|
||||
data.writeByte (g);
|
||||
data.writeByte (r);
|
||||
data.writeByte (a);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
var andMask = new ByteArray (image.width * image.height);
|
||||
|
||||
for (y in 0...image.height) {
|
||||
|
||||
pixels.position = (image.height - 1 - y) * 4 * image.width;
|
||||
|
||||
for (x in 0...image.width) {
|
||||
|
||||
a = pixels.readByte ();
|
||||
r = pixels.readByte ();
|
||||
g = pixels.readByte ();
|
||||
b = pixels.readByte ();
|
||||
|
||||
data.writeByte (b);
|
||||
data.writeByte (g);
|
||||
data.writeByte (r);
|
||||
data.writeByte (a);
|
||||
|
||||
// TODO: Fix the AND mask
|
||||
|
||||
//if (a < 128) {
|
||||
|
||||
//andMask.writeByte (1);
|
||||
|
||||
//} else {
|
||||
|
||||
andMask.writeByte (0);
|
||||
|
||||
//}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
data.writeBytes (andMask);
|
||||
|
||||
}
|
||||
|
||||
return data;
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
enum BMPType {
|
||||
|
||||
RGB;
|
||||
BITFIELD;
|
||||
ICO;
|
||||
|
||||
}
|
||||
39
lime/graphics/format/JPEG.hx
Normal file
39
lime/graphics/format/JPEG.hx
Normal file
@@ -0,0 +1,39 @@
|
||||
package lime.graphics.format;
|
||||
|
||||
|
||||
import lime.graphics.Image;
|
||||
import lime.system.System;
|
||||
import lime.utils.ByteArray;
|
||||
|
||||
|
||||
class JPEG {
|
||||
|
||||
|
||||
public static function encode (image:Image, quality:Int):ByteArray {
|
||||
|
||||
#if java
|
||||
|
||||
#elseif (sys && (!disable_cffi || !format))
|
||||
|
||||
return lime_image_encode (image.buffer, 1, quality);
|
||||
|
||||
#end
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Native Methods
|
||||
|
||||
|
||||
|
||||
|
||||
#if (cpp || neko || nodejs)
|
||||
private static var lime_image_encode:ImageBuffer -> Int -> Int -> ByteArray = System.load ("lime", "lime_image_encode", 3);
|
||||
#end
|
||||
|
||||
|
||||
}
|
||||
70
lime/graphics/format/PNG.hx
Normal file
70
lime/graphics/format/PNG.hx
Normal file
@@ -0,0 +1,70 @@
|
||||
package lime.graphics.format;
|
||||
|
||||
|
||||
import lime.graphics.Image;
|
||||
import lime.system.System;
|
||||
import lime.utils.ByteArray;
|
||||
|
||||
|
||||
class PNG {
|
||||
|
||||
|
||||
public static function encode (image:Image):ByteArray {
|
||||
|
||||
#if java
|
||||
|
||||
#elseif (sys && (!disable_cffi || !format))
|
||||
|
||||
return lime_image_encode (image.buffer, 0, 0);
|
||||
|
||||
#elseif !js
|
||||
|
||||
try {
|
||||
|
||||
var bytes = Bytes.alloc (image.width * image.height * 4 + image.height);
|
||||
var sourceBytes = image.buffer.data.getByteBuffer ();
|
||||
var sourceIndex:Int, index:Int;
|
||||
|
||||
for (y in 0...image.height) {
|
||||
|
||||
sourceIndex = y * image.width * 4;
|
||||
index = y * image.width * 4 + y;
|
||||
|
||||
bytes.set (index, 0);
|
||||
bytes.blit (index + 1, sourceBytes, sourceIndex, image.width * 4);
|
||||
|
||||
}
|
||||
|
||||
var data = new List ();
|
||||
data.add (CHeader ({ width: image.width, height: image.height, colbits: 8, color: ColTrue (true), interlaced: false }));
|
||||
data.add (CData (Deflate.run (bytes)));
|
||||
data.add (CEnd);
|
||||
|
||||
var output = new BytesOutput ();
|
||||
var png = new Writer (output);
|
||||
png.write (data);
|
||||
|
||||
return ByteArray.fromBytes (output.getBytes ());
|
||||
|
||||
} catch (e:Dynamic) {}
|
||||
|
||||
#end
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Native Methods
|
||||
|
||||
|
||||
|
||||
|
||||
#if (cpp || neko || nodejs)
|
||||
private static var lime_image_encode:ImageBuffer -> Int -> Int -> ByteArray = System.load ("lime", "lime_image_encode", 3);
|
||||
#end
|
||||
|
||||
|
||||
}
|
||||
@@ -14,6 +14,7 @@ import helpers.FileHelper;
|
||||
import helpers.ImageHelper;
|
||||
import helpers.LogHelper;
|
||||
import helpers.PathHelper;
|
||||
import lime.graphics.format.BMP;
|
||||
import lime.graphics.Image;
|
||||
import lime.math.Rectangle;
|
||||
import lime.utils.ByteArray;
|
||||
@@ -139,9 +140,9 @@ class IconHelper {
|
||||
public static function createWindowsIcon (icons:Array <Icon>, targetPath:String):Bool {
|
||||
|
||||
var sizes = [ 16, 24, 32, 40, 48, 64, 96, 128, 256 ];
|
||||
var images = new Array <Image> ();
|
||||
|
||||
var data_pos = 6;
|
||||
var images = new Array <Image> ();
|
||||
var imageData = new Array <ByteArray> ();
|
||||
|
||||
for (size in sizes) {
|
||||
|
||||
@@ -149,101 +150,56 @@ class IconHelper {
|
||||
|
||||
if (image != null) {
|
||||
|
||||
images.push (image);
|
||||
data_pos += 16;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var ico = new ByteArray ();
|
||||
ico.bigEndian = false;
|
||||
ico.writeShort (0);
|
||||
ico.writeShort (1);
|
||||
ico.writeShort (images.length);
|
||||
|
||||
for (image in images) {
|
||||
|
||||
var size = image.width;
|
||||
var xor_size = size * size * 4;
|
||||
var and_size = size * size >> 3;
|
||||
ico.writeByte (size);
|
||||
ico.writeByte (size);
|
||||
ico.writeByte (0); // palette
|
||||
ico.writeByte (0); // reserved
|
||||
ico.writeShort (1); // planes
|
||||
ico.writeShort (32); // bits per pixel
|
||||
ico.writeInt (40 + xor_size + and_size); // Data size
|
||||
ico.writeInt (data_pos); // Data offset
|
||||
data_pos += 40 + xor_size + and_size;
|
||||
|
||||
}
|
||||
|
||||
for (image in images) {
|
||||
|
||||
var size = image.width;
|
||||
var xor_size = size * size * 4;
|
||||
var and_size = size * size >> 3;
|
||||
|
||||
ico.writeInt (40); // size (bytes)
|
||||
ico.writeInt (size);
|
||||
ico.writeInt (size * 2);
|
||||
ico.writeShort (1);
|
||||
ico.writeShort (32);
|
||||
ico.writeInt (0); // Bit fields...
|
||||
ico.writeInt (xor_size + and_size); // Size...
|
||||
ico.writeInt (0); // res-x
|
||||
ico.writeInt (0); // res-y
|
||||
ico.writeInt (0); // cols
|
||||
ico.writeInt (0); // important
|
||||
|
||||
var bits = image.getPixels (new Rectangle (0, 0, size, size));
|
||||
var and_mask = new ByteArray ();
|
||||
|
||||
for (y in 0...size) {
|
||||
|
||||
var mask = 0;
|
||||
var bit = 128;
|
||||
bits.position = (size-1 - y) * 4 * size;
|
||||
|
||||
for (i in 0...size) {
|
||||
if (size < 256) {
|
||||
|
||||
var a = bits.readByte ();
|
||||
var r = bits.readByte ();
|
||||
var g = bits.readByte ();
|
||||
var b = bits.readByte ();
|
||||
ico.writeByte (b);
|
||||
ico.writeByte (g);
|
||||
ico.writeByte (r);
|
||||
ico.writeByte (a);
|
||||
imageData.push (BMP.encode (image, ICO));
|
||||
|
||||
if (a < 128)
|
||||
mask |= bit;
|
||||
} else {
|
||||
|
||||
bit = bit >> 1;
|
||||
|
||||
if (bit == 0) {
|
||||
|
||||
and_mask.writeByte (mask);
|
||||
bit = 128;
|
||||
mask = 0;
|
||||
|
||||
}
|
||||
imageData.push (image.encode ("png"));
|
||||
|
||||
}
|
||||
|
||||
images.push (image);
|
||||
|
||||
}
|
||||
|
||||
ico.writeBytes (and_mask, 0, and_mask.length);
|
||||
}
|
||||
|
||||
var icon = new ByteArray ();
|
||||
icon.bigEndian = false;
|
||||
icon.writeShort (0);
|
||||
icon.writeShort (1);
|
||||
icon.writeShort (images.length);
|
||||
|
||||
var dataOffset = 6 + (16 * images.length);
|
||||
|
||||
for (i in 0...images.length) {
|
||||
|
||||
var size = images[i].width;
|
||||
|
||||
icon.writeByte (size > 255 ? 0 : size);
|
||||
icon.writeByte (size > 255 ? 0 : size);
|
||||
icon.writeByte (0);
|
||||
icon.writeByte (0);
|
||||
icon.writeShort (1);
|
||||
icon.writeShort (32);
|
||||
icon.writeInt (imageData[i].length);
|
||||
icon.writeInt (dataOffset);
|
||||
|
||||
dataOffset += imageData[i].length;
|
||||
|
||||
}
|
||||
|
||||
for (data in imageData) {
|
||||
|
||||
icon.writeBytes (data);
|
||||
|
||||
}
|
||||
|
||||
if (images.length > 0) {
|
||||
|
||||
var file = File.write (targetPath, true);
|
||||
file.writeBytes (ico, 0, ico.length);
|
||||
file.close ();
|
||||
|
||||
File.saveBytes (targetPath, icon);
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user