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.BytesInput;
|
||||||
import haxe.io.BytesOutput;
|
import haxe.io.BytesOutput;
|
||||||
import lime.app.Application;
|
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.ImageCanvasUtil;
|
||||||
import lime.graphics.utils.ImageDataUtil;
|
import lime.graphics.utils.ImageDataUtil;
|
||||||
import lime.math.ColorMatrix;
|
import lime.math.ColorMatrix;
|
||||||
@@ -292,54 +295,15 @@ class Image {
|
|||||||
|
|
||||||
case "png":
|
case "png":
|
||||||
|
|
||||||
#if java
|
return PNG.encode (this);
|
||||||
|
|
||||||
#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
|
|
||||||
|
|
||||||
case "jpg", "jpeg":
|
case "jpg", "jpeg":
|
||||||
|
|
||||||
#if java
|
return JPEG.encode (this, quality);
|
||||||
|
|
||||||
|
case "bmp":
|
||||||
|
|
||||||
#elseif (sys && (!disable_cffi || !format))
|
return BMP.encode (this);
|
||||||
|
|
||||||
return lime_image_encode (buffer, 1, quality);
|
|
||||||
|
|
||||||
#end
|
|
||||||
|
|
||||||
default:
|
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.ImageHelper;
|
||||||
import helpers.LogHelper;
|
import helpers.LogHelper;
|
||||||
import helpers.PathHelper;
|
import helpers.PathHelper;
|
||||||
|
import lime.graphics.format.BMP;
|
||||||
import lime.graphics.Image;
|
import lime.graphics.Image;
|
||||||
import lime.math.Rectangle;
|
import lime.math.Rectangle;
|
||||||
import lime.utils.ByteArray;
|
import lime.utils.ByteArray;
|
||||||
@@ -139,9 +140,9 @@ class IconHelper {
|
|||||||
public static function createWindowsIcon (icons:Array <Icon>, targetPath:String):Bool {
|
public static function createWindowsIcon (icons:Array <Icon>, targetPath:String):Bool {
|
||||||
|
|
||||||
var sizes = [ 16, 24, 32, 40, 48, 64, 96, 128, 256 ];
|
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) {
|
for (size in sizes) {
|
||||||
|
|
||||||
@@ -149,101 +150,56 @@ class IconHelper {
|
|||||||
|
|
||||||
if (image != null) {
|
if (image != null) {
|
||||||
|
|
||||||
images.push (image);
|
if (size < 256) {
|
||||||
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) {
|
|
||||||
|
|
||||||
var a = bits.readByte ();
|
imageData.push (BMP.encode (image, ICO));
|
||||||
var r = bits.readByte ();
|
|
||||||
var g = bits.readByte ();
|
|
||||||
var b = bits.readByte ();
|
|
||||||
ico.writeByte (b);
|
|
||||||
ico.writeByte (g);
|
|
||||||
ico.writeByte (r);
|
|
||||||
ico.writeByte (a);
|
|
||||||
|
|
||||||
if (a < 128)
|
} else {
|
||||||
mask |= bit;
|
|
||||||
|
|
||||||
bit = bit >> 1;
|
imageData.push (image.encode ("png"));
|
||||||
|
|
||||||
if (bit == 0) {
|
|
||||||
|
|
||||||
and_mask.writeByte (mask);
|
|
||||||
bit = 128;
|
|
||||||
mask = 0;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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) {
|
if (images.length > 0) {
|
||||||
|
|
||||||
var file = File.write (targetPath, true);
|
File.saveBytes (targetPath, icon);
|
||||||
file.writeBytes (ico, 0, ico.length);
|
|
||||||
file.close ();
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user