Root cause of problem found:
Perl misprints a ushort with %hu format as %c%c
Does Perl have a PrintC function which prints C datatypes
EXACTLY as C would print the same BINARY DIGITS without
dismembering multi-byte integers and misprinting as
single-byte character data? %hu means %hu, !%c%c!
This behavior contradicts sprintf documentation:
Size: h interpret integer as C type "short"
It contradicts C behavior; same data, same printf, wrong result
It fails the intelligent assistant test:
What is the value of $Xres? "+^\" is !correct
Working with uint16 image data without a printf which
understands the difference between characters and ushorts
is a problem. Does one keep 2, parallel sets of data,
1 real set for Photoshop and a second, "doctored" set
to print correctly in the log files?
Test case: 1) pack number into 'S', unsigned short, store in $pxres 2) write $pxres to disk in binary mode 3) dump this file in C to verify contents 4) Include misprint of uint16 as 2 uint8s in C output 5) print $pxres variable in Perl with explicit %d, %hu, %s... Results: Perl does pack and dump uint16 containing number 7360 correctly. Contents verified via C program Perl prints the known good uint16 as 2 uint8 chars Perl printf of 7360 with explicit "%hu" format is identical to C printf of uint16 buffer with %c%c I asked a "2 foot section of rope". Assistant delivered 2, "1 foot sections of rope".--------------------------------------------------------
RTFM background: http://perldoc.perl.org/functions/sprintf.html Size: h interpret integer as C type "short" or "unsigned short" %u an unsigned integer, in decimal %hu -> unsigned C type "short" This is Exactly the contents of the Perl variable as verified by C
Test program ouput: Running C:\bin\bb.pl Wed Jan 6 13:26:28 2016 Perl: Pack number 7360 into uint16 and dump to file pack.test.dat hex_dec_bin_dump.exe File pack.test.dat is 2 bytes long Read 2 Bytes from pack.test.dat Int 7360, uint16 7360, hex 0X1CC0, float 7360.0000, binary 11100110000 +00 BAD_PRINT, Show uint16 as chars: 7360 != +? Argument "+^\" isn't numeric in printf at C:\bin\bb.pl line 179, <FOO> + line 168. Number 7360 Packed into 'S': h 0, d 0, hu 0, b 0, s +?
------------------------------------------------Perl Code: sub perl_pack_print() { $ofn='pack.test.dat'; # Output file Name $xres=7360; # X Resolution $pxres=pack("S", $xres); # Xres Packed into USHORT open(O, ">$ofn"); binmode O; print(O "$pxres"); close O; print("Perl: Pack number $xres into uint16 and dump to file $ofn\n +"); # Verify that Perl wrote the correct data to disk system("hex_dec_bin_dump.exe $ofn"); # See if Perl can print the '%hu' it just wrote to disk printf("Number $xres Packed into 'S': h %x, d %d, hu %hu, b %b, s +%s\n", $pxres, $pxres, $pxres, $pxres, $pxres); }
=============================================================== =============================================================== Athanasius,C dump verification code: // Dump given file as hex, dec, float, string... // // gcc -Ofast -ffast-math -m64 -march=sandybridge -funroll-loops -fop +enmp -flto -lm c:/bin/hex_dec_bin_dump.c -o c:/bin/hex_dec_bin_dump. +exe #include "bpbfct.c" void main(int argc, char *argv[]) { FILE *ifp; // FILE pointers to Output and Input file struct stat statbuf; // STAT function buffer long bread=-1; // Bytes Read int fsize=0; // File size from STAT() uint16_t usbuf[99]; // Unsigned Short BUFfer uint8_t *char_8_ptr; // Bytes to bisect/mutilate short char bitb[254]={ 0 }; // Bit Buffer. Should hold ANY integer char ifn[255]={ 0 }; strcpy(ifn, argv[1]); // Input File Name arg stat(ifn, &statbuf); // Stat the file to get its size fsize=statbuf.st_size; // File size in bytes for .raw (RGB?) file printf("\n%s\nFile %s is %d bytes long\n", argv[0], ifn, fsize); ifp=fopen(ifn, "rb"); // Open input file in bi +nary bread=fread((void *)usbuf, 1, 999, ifp); // Read argued file printf("Read %d Bytes from %s\n", bread, ifn); printf("Int %d, uint16 %hu, hex 0X%04X, float %.4f, binary %s\n", usbuf[0], usbuf[0], usbuf[0], (float)usbuf[0], itoa(usbuf[0], (char *)(&bitb), 2)); char_8_ptr=(uint8_t *) usbuf; // Cast ushort buf to uShortER printf("BAD_PRINT, Show uint16 as chars: %hu != %c%c\n\n", usbuf[0], char_8_ptr[0], char_8_ptr[1]); exit(0); } // End Main().
I tried the print instead of printf (and changed my variable name from rgb->hdr)
$hdr[16]=pack("S", 7360); $hdr[22]=pack("S", 4912); printf("FIXED? HDR[16]=$hdr[16], HDR[22]=$hdr[22]\n");
Read 1376 B from d:/pic/misc/gray.1376b.3689x2462.hdr RGB[16]=3689, [22]=2462 FIXED? HDR[16]=└∟, HDR[22]=0‼
This is NOT a print/f problem:
@hdr=unpack("S*", $hdr); # RAW RGB Unsigned Short array printf("PrInTf:: RGB[16]=%hu, [22]=%d\n", $hdr[16], $hdr[22]); print ("pRInT :: RGB[16]=$hdr[16], [22]=$hdr[22]\n"); => PrInTf:: RGB[16]=3689, [22]=2462 pRInT :: RGB[16]=3689, [22]=2462
It read, unpacked and printed raw, binary UINT16 data correctly
All I have been trying to do is: 1) document current value of uint16_t at some_uint16_array16 Try to imagine square brackets around the "<16>" above. 2) Convert ordinary integer <<7360>> to uint16_t 3) Overwrite old, documented value (the 3689) with new 7360 value 4) Confirm in log file that new value prints EXACTLY like old value 5) Write binary blob back to disk with only 2 uint16s changedHow does one PACK the "S"hort value "'7360'" into an array item created with:
open(H, "<$hfn"); binmode H; printf("Read $bread B from $hfn\n"); @hdr=unpack("S*", $hdr); # RAW RGB Unsigned Short array
A) It was asked to create an Unsigned SHORTfrom reasonable data: $hdr[\16\]=pack("S", 7360); B) It was asked to print it as an Unsigned SHORT as "%hu" C) It was asked to print the Unsigned SHORT as it saw fit D) How can it print this as:
The EXTRACTION part of the Pathological Extraction Report Lang is working!printf("FIXED? HDR[16]=$hdr[16], HDR[22]=$hdr[22]\n"); => FIXED? HDR[16]=└∟, HDR[22]=0‼
In reply to Re^4: Write 2 uint16_t numbers to file in Perl
by BrianP
in thread Write 2 uint16_t numbers to file in Perl
by BrianP
| For: | Use: | ||
| & | & | ||
| < | < | ||
| > | > | ||
| [ | [ | ||
| ] | ] |