I have 3 lines of C# Interop code that I am struggling to convert to ClosedXML. Can anyone please help?
str2 = worksheet.Range("B3", "L13").get_End(XlDirection.xlDown).get_Address(false, false, XlReferenceStyle.xlA1, System.Type.Missing, System.Type.Missing).Replace("B", "L");
object[,] objArray = (object[,]) worksheet.Range("B3", str2).Value;
str3 = worksheet.Range("B3", "L13").get_End(XlDirection.xlDown).get_Address(false, false, XlReferenceStyle.xlA1, System.Type.Missing, System.Type.Missing).Replace("B", "L");
Thanks
As answered here
This snipped looks overly complicated. First, you create a range from B3 to L13, then move down to the last row (getting to B13, apparently), then replace B to L which gives you L13 and finally you create a range B3:L13 once more to get the values from there.
ClosedXML does not have a built-in method to convert a range into a two-dimensional array but this can be easily done manually:
var range = worksheet.Range("B3:L13");
var objArray = new object[range.ColumnCount(), range.RowCount()];
for (int i = 0; i < range.ColumnCount(); i++)
{
for (int j = 0; j < range.RowCount(); j++)
{
objArray[i, j] = range.Cell(j+1, i+1).Value;
}
}
I'm trying to write Array(1, 2) to binary file as bytes.
So output file should contain 00000001 00000010.
I understood that I have to use ADODB.Stream, but I haven't found any solution for such simple task.
var data = new Array(1, 2)
out = WScript.CreateObject("ADODB.Stream")
out.Type = 1
out.Open()
out.Write(data)
out.SaveToFile("output.bin", 2)
out.Close()
Code above gives error:
Arguments are of the wrong type, are out of acceptable range, or are in conflict with one another.
Any ideas how to convert data array to acceptable type?
You can use the WriteAll function described here: Reading and Writing Binary Files Using JScript. Copyright: Dr Alexander J Turner.
Please note, the Stream shall be of type text, and then you will need to do the text<->binary conversion.
I just tested all the code and it worked fine for me.
Here is a complete example:
var bf1 = new BinaryFile("C:/Temp/test.bin");
var outBuf = '';
for(var i=0, l=data.length; i<l; i++) {
outBuf += String.fromCharCode(data[i]);
}
bf1.WriteAll(outBuf);
The result looks like this:
EDIT:
I just did a more compact adaptation of the code, to avoid the hex conversion and the double loop:
// Codepage conversion table
var _c=[199,252,233,226,228,224,229,231,234,235,232,239,238,236,196,197,
201,230,198,244,246,242,251,249,255,214,220,162,163,165,8359,402,
225,237,243,250,241,209,170,186,191,8976,172,189,188,161,171,187,
9617,9618,9619,9474,9508,9569,9570,9558,9557,9571,9553,9559,9565,9564,9563,9488,
9492,9524,9516,9500,9472,9532,9566,9567,9562,9556,9577,9574,9568,9552,9580,9575,
9576,9572,9573,9561,9560,9554,9555,9579,9578,9496,9484,9608,9604,9612,9616,9600,
945,223,915,960,931,963,181,964,934,920,937,948,8734,966,949,8745,
8801,177,8805,8804,8992,8993,247,8776,176,8729,183,8730,8319,178,9632,160],
_w=[],
_r=[];
// Create forward lookup to write & reverse lookup to read
for(var i=0, l=256; i<l; i++) {
var c = (i<128) ? i : _c[i-128];
_w[i] = c;
_r[c] = i;
}
// Read binary data from disk
function binFileToArray(fileName, binArray){
var inStream = new ActiveXObject("ADODB.Stream");
inStream.Type = 2;
inStream.CharSet = '437';
inStream.Open();
inStream.LoadFromFile(fileName);
var inString = inStream.ReadText();
inStream.Close();
for(var i=0, l=inString.length; i<l; i++) {
binArray.push(_r[inString.charCodeAt(i)]);
}
}
// Write binary data to disk
function binArrayToFile(binArray, fileName){
var outStream = new ActiveXObject('ADODB.Stream');
var outString = '';
for(var i=0, l=binArray.length; i<l; i++) {
outString += String.fromCharCode(_w[binArray[i]]);
}
outStream.Type = 2;
outStream.CharSet = '437';
outStream.Open();
outStream.WriteText(outString);
outStream.SaveToFile(fileName, 2);
outStream.Close();
}
// TEST: read binary file from disk & write array back to disk
var testArray = [];
binFileToArray('c:/temp/test.bin', testArray);
binArrayToFile(testArray, 'c:/temp/test2.bin');
// both files equals
Im using a very big BitmapData as a pathing map for my platformer game, however I only use pixels for 4 particular values, instead of, well 4294967295.
Would converting this Bitmapdata as 2 2D Vectors of Boolean save me some memory ?
And if it does, what about performance, would it be faster or slower to do something like:
MapGetPixel(x:int, y:int):int
{
return MapBoolFirst[x][y] + MapBoolSecond[x][y]*2;
}
instead of the bitmapdata class getPixel32(x:int, y:int):uint ?
In short im looking for a way to reduce the size and/or optimize my 4 colors bitmapdata.
Edit :
Using my boolean method apparently consumes 2 times more memory than the bitmapdata one.
I guess a boolean takes more than one bit in memory, else that would be too easy. So im thinking about bitshifting ints and thus have an int store the value for several pixels, but im not sure about this…
Edit 2 :
Using int bitshifts I can manage the data of 16 pixels into a single int, this trick should work to save some memory, even if it'll probably hit performance a bit.
Bitshifting will be the most memory-optimized way of handling it. Performance wise, that shouldn't be too big of an issue unless you need to poll a lot of asks each frame. The issue with AS is that booleans are 4bits :(
As I see it you can handle it in different cases:
1) Create a lower res texture for the hit detections, usually it is okay to shrink it 4 times (256x256 --> 64x64)
2) Use some kind of technique of saving that data into some kind of storage (bool is easiest, but if that is too big, then you need to find another solution for it)
3) Do the integer-solution (I haven't worked with bit-shifting before, so I thought it would be a fun challenge, here's the result of that)
And that solution is way smaller than the one used for boolean, and also way harder to understand :/
public class Foobar extends MovieClip {
const MAX_X:int = 32;
const MAX_Y:int = 16;
var _itemPixels:Vector.<int> = new Vector.<int>(Math.ceil(MAX_X * MAX_Y / 32));
public function Foobar() {
var pre:Number = System.totalMemory;
init();
trace("size=" + _itemPixels.length);
for (var i = 0; i < MAX_Y; ++i) {
for (var j = 0; j < MAX_X; ++j) {
trace("item=" + (i*MAX_X+j) + "=" + isWalkablePixel(j, i));
}
}
trace("memory preInit=" + pre);
trace("memory postInit=" + System.totalMemory);
}
public function init() {
var MAX_SIZE:int = MAX_X * MAX_Y;
var id:int = 0;
var val:int = 0;
var b:Number = 0;
for(var y=0; y < MAX_Y; ++y) {
for (var x = 0; x < MAX_X; ++x) {
b = Math.round(Math.random()); //lookup the pixel from some kind of texture or however you expose the items
if (b == 1) {
id = Math.floor((y * MAX_X + x) / 32);
val = _itemPixels[id];
var it:uint = (y * MAX_X + x) % 32;
b = b << it;
val |= b;
_itemPixels[id] = val;
}
}
}
}
public function isWalkablePixel(x, y):Boolean {
var val:int = _itemPixels[Math.floor((y * MAX_X + x) / 32)];
var it:uint = 1 << (y * MAX_X + x) % 32;
return (val & it) != 0;
}
}
One simple improvement is to use a ByteArray instead of BitmapData. That means each "pixel" only takes up 1 byte instead of 4. This is still a bit wasteful since you're only needing 2 bits per pixel and not 8, but it's a lot less than using BitmapData. It also gives you some "room to grow" without having to change anything significant later if you need to store more than 4 values per pixel.
ByteArray.readByte()/ByteArray.writeByte() works with integers, so it's really convenient to use. Of course, only the low 8 bits of the integer is written when calling writeByte().
You set ByteArray.position to the point (0-based index) where you want the next read or write to start from.
To sum up: Think of the ByteArray as a one dimensional Array of integers valued 0-255.
Here are the results, I was using an imported 8 bit colored .png by the way, not sure if it changes anything when he gets converted into a
BitmapData.
Memory usage :
BitmapData : 100%
Double Boolean vectors : 200%
Int Bitshifting : 12%
So int bitshifting win hands down, it works pretty much the same way as hexadecimal color components, however in that case I store 16 components (pixel values in 2 bits) not the 4 ARGB:
var pixels:int = -1;// in binary full of 1
for (var i:int = 0; i < 16; i++)
trace("pixel " + (i + 1) +" value : " + (pixels >> i * 2 & 3));
outputs as expected :
"pixel i value : 3"
I'm using MySql and Nodejs. I need to store a huge string made of only 0s and 1s. (This is a map grid. 0 = Can Move, 1 = Can't move.)
Ex: 00000000000000000000000000000000000010000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000010000000000
...
Should I take that string, encode it into a base64 string and store it that way? Then when I need it, I decode it? If so, how would I do it, using Nodejs/Javascript?
Thanks
The data you're storing appears to compress easily, why don't you use the built-in MySql COMPRESS function
Raw:
mysql> select length('00000000000000000000000000000000000010000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000010000000000');
332
With COMPRESS
mysql> select length(compress('00000000000000000000000000000000000010000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000010000000000'));
23
Don't store a string, store binary.
Here's an example of a way you could convert that data to binary. Hopefully you can reengineer things so that your map data is never represented as a string in the first place.
static void Main(string[] args)
{
const string data =
"00000000000000000000000000000000000010000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000010000000000";
var arrayLength = data.Length/8;
if (data.Length%8 != 0)
arrayLength++;
var binaryData = new byte[arrayLength];
byte nextByte=0;
var k = -1;
for (var i = 0; i < data.Length; i++)
{
var j = i%8;
if (j == 0)
{
binaryData[++k] = nextByte;
nextByte = 0;
}
var bit = int.Parse(data[i].ToString());
if(bit==1)
nextByte |= (byte)(bit << j);
}
binaryData[k] = nextByte;
}
hello i am using this code for animating a sprite using cocos2dx.
CCSpriteFrameCache::sharedSpriteFrameCache()->addSpriteFramesWithFile("suhas.plist");
CCLog("#########################");
CCSpriteBatchNode *spriteSheet = CCSpriteBatchNode::batchNodeWithFile("suhas.PNG");
CCLog("*********************************");
this->addChild(spriteSheet);
CCLog("*********************************");
CCArray *bearArray = new CCArray();
for(int i = 1; i <= 8; i++)
{
CCLog("*********************************");
char name[32] = {0};
sprintf(name, "bear%d.png",i);
bearArray->addObject(CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName(name));
}
CCAnimation *walkAnim = CCAnimation::animationWithSpriteFrames(bearArray, 0.1f);
CCSize size = CCDirector::sharedDirector()->getWinSize();
CCSprite *bear = CCSprite::spriteWithSpriteFrameName("bear1.png");
bear->setPosition(ccp(size.width/2, size.height/2));
CCAction *walkAction = CCRepeatForever::actionWithAction(CCAnimate::actionWithAnimation(walkAnim));
bear->runAction(walkAction);
spriteSheet->addChild(bear);
return true;
But my code in crashing. and giving error
cocos2d: CCSpriteFrameCache: Trying to use file D:\cocos2dnew\SPRITEAnimDemo\Resources\suhas.png as texture
First-chance exception at 0x00000000 in SPRITEAnimDemo.win32.exe: 0xC0000005: Access violation.
Unhandled exception at 0x00000000 in SPRITEAnimDemo.win32.exe: 0xC0000005: Access violation.
The program '[1012] SPRITEAnimDemo.win32.exe: Native' has exited with code -1073741819 (0xc0000005).
I tried on google for solving this problem. Please help me.
Change this line
*spriteSheet = CCSpriteBatchNode::batchNodeWithFile("suhas.PNG");
with
*spriteSheet = CCSpriteBatchNode::batchNodeWithFile("suhas.png");
In newer version of cocos2d-x you can add batchnode first :
SpriteFrameCache::getInstance()->addSpriteFramesWithFile("sprite_sheet.plist");
_gameBatchNode = SpriteBatchNode::create("sprite_sheet.png");
this->addChild(_gameBatchNode, 1);
for animation :
auto animation = Animation::create();
int i;
for(i = 1; i <= 10; i++) {
auto name = String::createWithFormat("boom%i.png", i);
//auto name = String::createWithFormat("meteor-%i.png", i);
auto frame = SpriteFrameCache::getInstance()->getSpriteFrameByName(name->getCString());
animation->addSpriteFrame(frame);
}
animation->setDelayPerUnit(1 / 10.0f);
animation->setRestoreOriginalFrame(true);
note that boom.png & meteor.png is inside sprite_sheet.plist