How to generate 2 pixel BMP image with Awk? - image

sorry for the silly question, but I'm trying to create (generate) a simple BMP image 2x1, 24-bit bitmap with pixel format RGB24, using Awk.
Format is "BitmapFileHeader (2+4+4+4=14 bytes) + DIBHeader (4+4+4+2+2+4+4+4+4+4+4=40 bytes) = 54byte", then start of pixel array (bitmap data). Here is my simple script:
BEGIN {
ORS="";
filebmp="Image.bmp"
# BMP Header: 2+4+4+4=14 bytes
printf("%c%c",66,77)>filebmp;
printf("%c%c%c%c",62,0,0,0)>filebmp;
printf("%c%c%c%c",0,0,0,0)>filebmp;
printf("%c%c%c%c",54,0,0,0)>filebpm;
# DIB Header: 4+4+4+2+2+4+4+4+4+4+4=40 bytes
printf("%c%c%c%c",40,0,0,0)>filebmp;
printf("%c%c%c%c",2,0,0,0)>filebmp;
printf("%c%c%c%c",1,0,0,0)>filebmp;
printf("%c%c",1,0)>filebmp;
printf("%c%c",24,0)>filebmp;
printf("%c%c%c%c",0,0,0,0)>filebmp;
printf("%c%c%c%c",8,0,0,0)>filebmp;
printf("%c%c%c%c",19,11,0,0)>filebmp;
printf("%c%c%c%c",19,11,0,0)>filebmp;
printf("%c%c%c%c",0,0,0,0)>filebmp;
printf("%c%c%c%c",0,0,0,0)>filebmp;
# start of pixel array (bitmap data)
# Blu pixel
printf ("%c%c%c",127,0,0)>filebmp;
# Green pixel
printf ("%c%c%c",0,127,0)>filebmp;
# Padding
printf ("%c%c",0,0)>filebmp;
}
it's works (image below): it generates a BMP image 2x1 and 62 byte size.
http://i60.tinypic.com/mlihyt.jpg
But, now, if in the bitmap data I substitute 127 value with 128 (e.g. in blue pixel), same script Awk generates a BMP image 2x1 but 63 byte size and with "other colours" (see image below)!
http://i62.tinypic.com/2ltkjlg.png
I wonder where I am going wrong...
...any ideas?
Thanks & Bye

I was able to reproduce the issue with gawk. It seems that gawk chooses the output encoding based on your LANG environment variable. (Here I've change both instances of 127 to 128.)
$ LANG=en_US.LATIN1 gawk -f bit.awk
$ wc -c Image.bmp
62 Image.bmp
00000000: 424d 3e00 0000 0000 0000 3600 0000 2800 BM>.......6...(.
00000010: 0000 0200 0000 0100 0000 0100 1800 0000 ................
00000020: 0000 0800 0000 130b 0000 130b 0000 0000 ................
00000030: 0000 0000 0000 8000 0000 8000 0000 ..............
$ LANG=en_US.UTF-8 gawk -f bit.awk
$ wc -c Image.bmp
64 Image.bmp
00000000: 424d 3e00 0000 0000 0000 3600 0000 2800 BM>.......6...(.
00000010: 0000 0200 0000 0100 0000 0100 1800 0000 ................
00000020: 0000 0800 0000 130b 0000 130b 0000 0000 ................
00000030: 0000 0000 0000 c280 0000 00c2 8000 0000 ................
Run gawk under a single-byte encoding and you should be fine.

Related

Why does this avi file with raw video yield only one frame=

I created an AVI file by rendering the frames using Cairo. The AVI generation code is part of an OCaml library. However, ffmpeg and vlc both yield only the very first frame. If I cut the avi header and use ffplay with the proper codec options, I can view the movie just fine.
What causes ffmpeg to think this file has only one frame?
The header of the file looks like this:
0000000 4952 4646 d0e0 0278 5641 2049 494c 5453
0000010 00c0 0000 6468 6c72 7661 6869 0038 0000
0000020 a2c2 0000 0000 0000 0000 0000 0100 0000
0000030 003c 0000 0000 0000 0001 0000 0000 0000
0000040 01e0 0000 01e0 0000 0000 0000 0000 0000
0000050 0000 0000 0000 0000 494c 5453 0074 0000
0000060 7473 6c72 7473 6872 0038 0000 6976 7364
0000070 4752 2042 0000 0000 0000 0000 0000 0000
0000080 000a 0000 00f0 0000 0000 0000 003c 0000
0000090 2000 00fd 0000 0000 0001 0000 0000 0000
00000a0 01e0 01e0 7473 6672 0028 0000 0028 0000
00000b0 01e0 0000 01e0 0000 0001 0018 0000 0000
00000c0 8c00 000a 0000 0000 0000 0000 0000 0000
00000d0 0000 0000 494c 5453 d00c 0278 6f6d 6976
00000e0 3030 6364 d000 0278 0000 0000 0000 0000
00000f0 0000 0000 0000 0000 0000 0000 0000 0000
I found the answer. Something not mentioned in the docs I read was that the stream itself needs to be encoded as a list of CHUNKS. So every frame shall be one CHUNK. This is, of course, not necessary in principle, but seems to be a very common convention.

How can I edit a binary file under windows by scripting

I'm usually a reader but this time I don't find an answer.
I've got some technical files produced by a scientific device.
From time to time, recorded files get corrupted and we have to do some hexadecimal modification by hand.
I'm wondering how I could automate it.
I was thinking of Perl, as I've got some knowledge in that, but even if I manage to read the offset of interest, I don't know how to write the new value.
I've got two things to do:
Write at offset 4 the size of the file minus 8
Count the number of "TRCKfmt" pattern, which is 5452434B666D74 in hex, then write it down at offset 5C (92) in hex value.
I've tried to use sysread and syswrite on a filehandle, but I can't get through the different steps.
Maybe Perl is not a good option, I don't know how to sort it out.
Here is my actual script:
use warnings;
use strict;
use diagnostics;
use Fcntl qw(:seek);
my($fh, $filename, $byte_position, $byte_value);
$filename = "MYFILE.tac";
$byte_position = 4;
my $filesize = -s $filename;
print "Size: $filesize\n";
open($fh, "<", $filename)
|| die "can't open $filename: $!";
binmode($fh)
|| die "can't binmode $filename";
sysseek($fh, $byte_position, SEEK_CUR) # NB: 0-based
|| die "couldn't see to byte $byte_position in $filename: $!";
sysread($fh, $byte_value, 1) == 1
|| die "couldn't read byte from $filename: $!";
printf "read byte with ordinal value %#02x at position %d\n",
ord($byte_value), $byte_position;
Thank you for any help.
Make it easy on yourself and just load the whole file in memory.
my $qfn = "MYFILE.tac";
my $file;
{
open(my $fh, '<:raw', $qfn)
or die("Can't open \"$qfn\": $!\n");
local $/;
$file = <$fh>;
}
{
my $packed_length = pack('N', length($file) - 8);
substr($file, 0x0004, length($packed_length), $packed_length);
}
{
my $num_blocks;
++$num_blocks while $file =~ /TRCKfmt/g;
my $packed_num_blocks = pack('N', $num_blocks);
substr($file, 0x005C, length($packed_num_blocks), $packed_num_blocks);
}
{
open(my $fh, '>:raw', $qfn)
or die("Can't create \"$qfn\": $!\n");
print($fh $file);
}
You didn't say in what format the number should be stored. I assumed they are 32-bit unsigned integers in big-endian byte order.
Let's create a file full of 0 bytes:
C:\...\> perl -E "binmode STDOUT; say qq{\0} x 32 for 1 .. 4" > test
C:\...\> xxd test
00000000: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000010: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000020: 0a00 0000 0000 0000 0000 0000 0000 0000 ................
00000030: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000040: 000a 0000 0000 0000 0000 0000 0000 0000 ................
00000050: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000060: 0000 0a00 0000 0000 0000 0000 0000 0000 ................
00000070: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000080: 0000 000a ....
The program below reads offsets and replacement bytes from the DATA section. You might want to put those in an external file:
#!/usr/bin/env perl
use strict;
use warnings;
use Fcntl qw(:seek);
#ARGV or die "Need filename\n";
my ($file) = #ARGV;
open my $fh, '+<:raw', $file
or die "Cannot open '$file': $!";
while (my $edit = <DATA>) {
next unless $edit =~ /\S/;
my ($offset, $value) = map hex, split ' ', $edit;
seek $fh, $offset, SEEK_SET
or die "Failed to seek to '$offset': $!";
print $fh chr($value)
or die "Failed to write new byte '$value' at offset '$offset': $!";
}
close $fh
or die "Failed to close '$file': $!";
__DATA__
0 64
8 65
10 61
18 64
20 62
28 65
30 65
38 66
40 20
After running the program:
C:\...\> xxd test
00000000: 6400 0000 0000 0000 6500 0000 0000 0000 d.......e.......
00000010: 6100 0000 0000 0000 6400 0000 0000 0000 a.......d.......
00000020: 6200 0000 0000 0000 6500 0000 0000 0000 b.......e.......
00000030: 6500 0000 0000 0000 6600 0000 0000 0000 e.......f.......
00000040: 200a 0000 0000 0000 0000 0000 0000 0000 ...............
00000050: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000060: 0000 0a00 0000 0000 0000 0000 0000 0000 ................
00000070: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000080: 0000 000a ....
Ok, thanks to #ikegami, here is the reply for this answer!
#!c:/Perl64/bin/perl.exe
use warnings;
use strict;
use diagnostics;
my $dir = 'MYDIRECTORY';
opendir DIR, $dir or die "cannot open dir $dir: $!";
my #files = glob "$dir/*.tac";
closedir(DIR);
foreach(#files){
my $qfn = $_;
my $file;
{
open(my $fh, '<:raw', $qfn)
or die("Can't open \"$qfn\": $!\n");
local $/;
$file = <$fh>;
}
{
my $packed_length = pack('V', length($file) - 8);
substr($file, 0x0004, length($packed_length), $packed_length);
}
{
my $num_blocks;
++$num_blocks while $file =~ /TRCKfmt/g;
my $packed_num_blocks = pack('V', $num_blocks);
substr($file, 0x005C, length($packed_num_blocks), $packed_num_blocks);
}
{
open(my $fh, '>:raw', $qfn)
or die("Can't create \"$qfn\": $!\n");
print($fh $file);
}
}
Thanks you Stackoverflow guys, that's really helpful

Use bitwise AND with string on ruby on rails

I want use bitwise operator "&" with string like that :
raw_counter_int = raw_counter.to_i
raw_counter_bin = raw_counter_int.to_s(2)
u = (2**62 + 2**63)
k = u.to_s(2)
r = raw_counter_bin & k
#counter_msg = r
but when I run my application I've this error message :
undefined method `&' for "10000000000000000000000000000000000000000000000000000000":String
How I can use this operator "&" with raw_counter_int and u which are converted in binary ?
I try with this: 0000 0000 1000 0000 0000 0000 0000 0000 (64 bits) to
take bytes between the third bytes and the 10th bytes. So I want do a
bitwise "&" with 0000 0000 1000 0000 0000 0000 0000 0000 & 0011 1111
1100 0000 0000 0000 0000 0000 to take just this : 00 0000 10
I try with this: 0000 0000 1000 0000 0000 0000 0000 0000 (64 bits) to
take bytes between the third bytes and the 10th bytes. So I want do a
bitwise "&" with 0000 0000 1000 0000 0000 0000 0000 0000 & 0011 1111
1100 0000 0000 0000 0000 0000 to take just this : 00 0000 10
Let's do it:
("00000000100000000000000000000000".to_i(2) & "00111111110000000000000000000000".to_i(2)).to_s(2)
=> "100000000000000000000000"
Which is exactly what is expected! The number shown in the error ("10000000000000000000000000000000000000000000000000000000") is 2^56, which, when using bitwise AND with it and 2^62+2^63 is expected to give you a zero result...
I suggest you check your input again, and trust ruby's & to do the job...

how to convert a binary file to human read able

I have a binary file of a Fortran program. For this binary file want to know the source coding of the Fortran program. By using hexdum -c I have converted the binary file to ascii file. Still it is not understandable. How to convert a binary file or ascii file to human readable format.
Below I have past the some portion of ascii file after doing hexdum -c
0003D80 0000 0000 0100 1300 8901 0000 D8B4 0408
0003D90 0000 0000 0100 1000 9701 0000 CCB5 0408
0003DA0 0000 0000 0100 1400 A301 0000 B09D 0408
0003DB0 0000 0000 0200 0C00 B901 0000 0000 0000
0003DC0 0000 0000 0400 F1FF BE00 0000 0000 0000
0003DD0 0000 0000 0400 F1FF EE00 0000 0000 0000
0003DE0 0000 0000 0400 F1FF B901 0000 0000 0000
0003DF0 0000 0000 0400 F1FF 0100 0000 0000 0000
0003E00 0000 0000 0400 F1FF 1000 0000 0000 0000
0003E10 0000 0000 0400 F1FF 0100 0000 0000 0000
0003E20 0000 0000 0400 F1FF 3E00 0000 0000 0000
0003E30 0000 0000 0400 F1FF B901 0000 0000 0000
0003E40 0000 0000 0400 F1FF E901 0000 0000 0000
0003E50 0000 0000 0400 F1FF F201 0000 00B1 0408
0003E60 1400 0000 0100 0F00 0302 0000 14B1 0408
0003EE0 1400 0000 0100 0F00 8B02 0000 B4B1 0408
0003EF0 1400 0000 0100 0F00 9C02 0000 C8B1 0408
0003F00 1400 0000 0100 0F00 AF02 0000 DCB1 0408
0003F10 1400 0000 0100 0F00 C202 0000 F0B1 0408
0003F20 1400 0000 0100 0F00 D502 0000 04B2 0408
0003F30 1400 0000 0100 0F00 E802 0000 18B2 0408
0003F40 1400 0000 0100 0F00 FB02 0000 2CB2 0408
There are decompilers which will attempt to generate source code from the binary, but it would not be the original source code. Meaning it would not have comments or local variable names. In order to get a decompiler for your binary though, you have to find out which compiler was used to generate it, then which architecture it was compiled for. The next step would be to search for a decompiler for that compiler, or a decompiler for that architecture which is similar enough to the compilation techniques used on the original compiler to generate reasonable source code.
The binary file you gave (since it's a compiled program) isn't just a binary representation of ASCII or any other text code. The reason is that It's machine code, meaning that it doesn't translate into anything human readable.
Some other people have mentioned, there are some decompilers which attempt to reverse the compile process (but those wouldn't give variable names and comments).
If it's an open source program you're trying to find the source code for, you should be able to find it somewhere online (like on sourceforge.net)

awk instead of sed is not working (slow, laggy and wrong output)

Why is awk not working for the following command instead of sed:
su -c "stdbuf -i0 -o0 -e0 od --width=144 -x /dev/input/event3 | sed 's%^\([a-z0-9]\+ \)\{11\}%%;s%\(....\).*%\1%'"
This prints at every keypress the USB HID ID number of the key that was pressed.
Example output (0028 is for Return and 00e4 for Right-Ctrl):
0028
0028
0028
0028
0028
00e4
00e4
00e4
This are two lines of output without sed/cut/awk filtering when pressing Return two times. The USB HID ID number is in column 12:
0000000 2d6f 511e 0000 0000 051b 0007 0000 0000 0004 0004 0028 0007 2d6f 511e 0000 0000 051d 0007 0000 0000 0001 001c 0000 0000 2d6f 511e 0000 0000 051e 0007 0000 0000 0000 0000 0000 0000 2d73 511e 0000 0000 a150 0007 0000 0000 0004 0004 0028 0007 2d73 511e 0000 0000 a153 0007 0000 0000 0001 001c 0001 0000 2d73 511e 0000 0000 a154 0007 0000 0000 0000 0000 0000 0000
0000220 2d73 511e 0000 0000 9b5a 0008 0000 0000 0004 0004 0028 0007 2d73 511e 0000 0000 9b5d 0008 0000 0000 0001 001c 0000 0000 2d73 511e 0000 0000 9b5e 0008 0000 0000 0000 0000 0000 0000 2d74 511e 0000 0000 4f90 0005 0000 0000 0004 0004 0028 0007 2d74 511e 0000 0000 4f93 0005 0000 0000 0001 001c 0001 0000 2d74 511e 0000 0000 4f94 0005 0000 0000 0000 0000 0000 0000
I tried it with
su -c "stdbuf -i0 -o0 -e0 od --width=144 -x /dev/input/event3 | cut -d' ' -f12"
and it also works. But it only shows the keys pressed after the next two keypresses. stdbuf did not help here, although it should adjusts standard input/output/error stream buffering to 0.
My mawk command looked like this:
su -c "stdbuf -i0 -o0 -e0 od --width=$((48*3)) -x /dev/input/event3 | mawk '{ print $12 }'"
but it only showed me some twos and then some newlines and again twos. It seems very laggy/slow. When I press a key, nothing happens. After pressing different keys multiple times, I always get a bunch of twos and newlines. No matter which keys I pressed! Example:
2
2
2
2
2
2
2
2
2
2
2
2
How can I fix this? Why is this occurring?
Update
When I use gawk instead of mawk it does not lag any more (unbuffered). But I still don’t see the correct values which should be 0028 or 00e4 and so on for Return and Right-Ctrl as example keys.
With all the comments I came to the solution.
#Olivier Dulac brought me to the idea that there are different awk implementations, which solved the problem of the laggyness (using gawk instead of mawk). I don’t even need the stdbuf.
#Ed Morton’s idea brought me to a problem, because he used quotes " in his example. I already had quotes in my statement around the whole thing, because it was executed using su. So I had to escape them.
My whole statement looks like this (notice the escaped dollar sign in front of the 12):
su -c "od --width=144 -x /dev/input/event3 | awk '{ print \$12 }'"
and now it works as expected.

Resources