in reply to Write 2 uint16_t numbers to file in Perl

That is hard to read and interpret, but basically

use autodie ; open my($outfh),'>:raw', 'stuff'; print $outfh pack 'S<*', @rgb;

@rgb only contains numbers, when you write them to file you do the packing

Also don't use printf as a replacement for print

Replies are listed 'Best First'.
Re^2: Write 2 uint16_t numbers to file in Perl
by BrowserUk (Patriarch) on Jan 05, 2016 at 09:40 UTC
    What does this mean?
    Also don't use printf as a replacement for print

    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority". I knew I was on the right track :)
    In the absence of evidence, opinion is indistinguishable from prejudice.

      Possibly an allusion to the closing sentence in the documentation of the printf function?

      Don't fall into the trap of using a printf when a simple print would do. The print is more efficient and less error prone.

      Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

        UPDATE:
        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); }
        ------------------------------------------------
        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().
        =============================================================== =============================================================== Athanasius,

        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]=&#9492;&#8735;, HDR[22]=0&#8252;

        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 changed
        
        How 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:
        

        printf("FIXED? HDR[16]=$hdr[16], HDR[22]=$hdr[22]\n"); => FIXED? HDR[16]=&#9492;&#8735;, HDR[22]=0&#8252;
        The EXTRACTION part of the Pathological Extraction Report Lang is working!
        The DATA CREATION seems to have fallen less on the PRACTICAL side :)

      This solution works PERFECTLY as documented

      // Grab a standard TIF hdr // Update the ushort XY res values, X@[16] and Y@[22] // Slam it on top of a UINT16 RAW and call it a TIF!!! // What could POSSIBLY be easier??? // // gcc -Ofast -ffast-math -m64 -march=sandybridge -msse4.2 -mavx -fun +roll-loops -fopenmp -flto -lm c:/bin/merge.hdr.raw.c -o c:/bin/merge +.hdr.raw.exe #include "bpbfct.c" void main(int argc, char *argv[]) { FILE *hi, *ri, *to; // File pointers for 2 ins and 1 outs struct stat statbuf; // STAT function buffer char hdrfn[255] = { 0 }; char rawfn[255] = { 0 }; char tiffn[] = "hdr.raw.merge.tif"; int hsize=1376, rsize, bread, brote, tsize; // Header and RAW sizes uint16_t *hdra; // HDR data array uint16_t *rawa; // RAW data array strcpy(hdrfn, argv[1]); strcpy(rawfn, argv[2]); hdra=(uint16_t *)malloc(hsize); hi=fopen(hdrfn, "rb"); bread=fread((void *)hdra, 1, hsize, hi); printf("Read %d Bytes from %s\n", bread, hdrfn); fclose(hi); stat(rawfn, &statbuf); // Stat the file to get its size rsize=statbuf.st_size; // File size in bytes for .raw (RGB?) file rawa=(uint16_t *)malloc(rsize); ri=fopen(rawfn, "rb"); bread=fread((void *)rawa, 1, rsize, ri); printf("Read %.6lf MBytes from %s\n", bread*1E-6, rawfn); fclose(ri); // HERE's the HARD PART!!! printf("Xres @ Hdr[16]=%hu, Yres @ [22] = %hu\n", hdra[16], hdra[2 +2]); hdra[16]=(uint16_t) 7360; <<<< Is this POSSIBLE in PERL?????? hdra[22]=(uint16_t) 4912; // Did it float?? printf("FIXED?? Xres @ Raw[16]=%hu, Yres [22] = %hu\n", hdra[16], hdra[22]); to=fopen(tiffn, "wb"); // TIF output file brote = fwrite((void *)(hdra), 1, hsize, to); brote += fwrite((void *)(rawa), 1, rsize, to); fflush(to); fflush(to); fclose(to); stat(tiffn, &statbuf); // Stat the file to get its size tsize=statbuf.st_size; // File size in bytes for .raw (RGB?) file printf("Wrote %.6lf MBytes to TIF %s, Size: T-R-H=%d\n", tsize*1E-6, tiffn, brote - rsize - hsize); free(hdra); free(rawa); } // End Main().
      I:\exp\6s-254623> merge.hdr.raw.exe gray.1376b.3689x2462.hdr 6s-2015 +.1031-254550.7360x4912.blue.cv.t.raw Read 1376 Bytes from gray.1376b.3689x2462.hdr Read 72.304640 MBytes from 6s-2015.1031-254550.7360x4912.blue.cv.t.raw Xres @ Hdr[16]=3689, Yres @ [22] = 2462 FIXED?? Xres @ Raw[16]=7360, Yres [22] = 4912 Wrote 72.306016 MBytes to TIF hdr.raw.merge.tif, Size: T-R-H=0 I:\exp\6s-254623>identify hdr.raw.merge.tif hdr.raw.merge.tif TIFF 7360x4912 7360x4912+0+0 16-bit Grayscale Gray 7 +2.31MB ... <p> Note the original and overwritten values. </p> <code> Xres @ Hdr[16]=3689, Yres @ [22] = 2462 FIXED?? Xres @ Raw[16]=7360, Yres [22] = 4912 <<< WORKS!!!

      It's Alive!

      </code>

      What does this mean?

      This part use print  printf("Read $bread B from $hfn\n");

        Right. I missed that.

        Then again, it wouldn't be that hard for printf to realise that it only had a single parameter and bypass inspecting the template and just print it. (Maybe that is already done.)


        With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority". I knew I was on the right track :)
        In the absence of evidence, opinion is indistinguishable from prejudice.