Fun With APNG & LC

Anything beyond the basics in using the LiveCode language. Share your handlers, functions and magic here.

Moderators: FourthWorld, heatherlaine, Klaus, kevinmiller, robinmiller

istech
Posts: 194
Joined: Thu Sep 19, 2013 10:08 am

Fun With APNG & LC

Post by istech » Fri Jan 29, 2021 4:55 pm

Hi All,

During lock down I thought I would have some fun in my spare time and see if it was possible to create an LC APNG player. I have found an online APNG decoder and the APNG spec which I was following. However I have had minimal success. I can export the images but they are corrupted. I'm thinking it has something to do with the CRC check. Maybe if you guys with much more experience than me have the time you can correct my mistakes and get it going.

The idea was to break up a APNG file and push it through an image object using the APNG parameters.

If anyone has a little spare time and wants to have a bit of fun please download and have a look. But please don't judge the code I was just experimenting.

Thanks

https://stackoverflow.com/questions/187 ... s-with-php

Code: Select all

on mouseUp pMouseButton
   put img "elephant.png" into test1
     
   put empty into tPic
   
   put byte 1 to 8 in test1 into tSig
   put 8 into toffset
   put the len of test1 into tSize
   --hex 76f6b354 7796403
   
   repeat until toffset >= tSize
      --error break
      add 1 to tcounter
      put byte toffset+1 to (toffset+4) in test1 into tLength
      add 4 to toffset
      
      put byte toffset+1 to (toffset+4) in test1 into tType
      add 4 to toffset
      
      // Unpack the length and read the chunk data including 4 byte CRC
      --$ilength = unpack('Nlength', $length); --output binary into array $length (convert decimal to binary array)
      --$ilength = $ilength['length']; --put the $length into array $ilength['length']
      --$chunk = substr($data, $offset, $ilength+4); --get the frame data $offset(from) (to)=($ilength+4) incl 4 byte CRC (remove first 4 bytes from chunk as it is sequence data)
      --$offset += $ilength+4; --adds 4 to the offset (why?)(maybe (maybe CRC)get ready for next chunk?)
      breakpoint
      put binaryDecode("M",tLength,sLength) into pLength --get the chunk lenght of frame
      --put tLength into tLength['length']
      if tType contains "fdAT" then
         
         put byte toffset+1 to ((toffset+1)+sLength) in test1 into tChunk --get location of frame and save to chunk
         
         --put byte 1 to 4 in tChunk into tChunkSequence
         --put binaryDecode("M",tChunkSequence,tChunkSequence) into pLength
         --put return & tChunkSequence after fld "seq"
         --breakpoint
         put byte +5 to -1 in tChunk into tChunk --remove 4 bytes sequence from start of chunk
         put sLength-4 into pLength --remove 4 byte sequnce from decimal length 
         
         put byte (toffset+1+sLength) to (toffset+sLength+4) in test1 into tCRCTest --test crc
      else
         put byte toffset+1 to (toffset+sLength+4) in test1 into tChunk --get location of frame and save to chunk
      end if
      
      --add 4 to toffset
      put toffset + (sLength+4) into toffset
      
      switch
         case tType contains "IHDR"
            --header
            --$header = $length . $type . $chunk;
            
            put byte -4 to -1 in tChunk into tCRC
            put binaryDecode("M",tCRC,sCRC) into pCRC
            
            put tLength & tType & tChunk into tHeader
            --breakpoint
            break
         case tType contains "IDAT"
            put tLength & tType & tChunk into tIDAT
            break
         case tType contains "IEND"
            breakpoint
            put tLength & tType & tChunk into tIEND
            break
         case tType contains "fdAT"
            
            --put char toffset to toffset+sLength in test1 into tChunk --just data and type should get a crc generated
            put "IDAT" before tChunk
            --generate crc
            put Crc32Str(tChunk)into scrc --hex
            --put "0x" before tcrc
            --breakpoint
            --put binaryDecode("M",tCRCTest,sCRCTest) into pCRCTest
            --breakpoint
            --put baseConvert(sCRCTest,10,10) into sCRCTest
            
            put baseConvert(scrc,16,10) into tcrc --hex to decimal
            
            put binaryEncode("M",tcrc) into tcrc --deciaml to binary
            
            --put char 11 to -9 of compress(tcrc) into tcrc
            --breakpoint
            put tcrc after tChunk
            --put char -4 to -1 of tChunk into tChunk --remove crc
            if fts is "65" then
               breakpoint
            end if
            put binaryEncode("M",pLength) into pLength --encode new length for file
            
            put pLength & tChunk into tPic --minus 4 from the length then convert to binary
            --$length . $type . $chunk; (parts)
            --$signature . $header . $parts[$i] . $end; (file)
            break
         case tType contains "fcTL"
            --breakpoint
            put byte 9 to 12 of tChunk into tw --width 480
            put binaryDecode("M",tw,fw) into ptw
            
            put byte 5 to 8 of tChunk into th --height 400
            put binaryDecode("M",th,fh) into pth
            
            put byte 1 to 4 of tChunk into ts --sequence 1
            put binaryDecode("M",ts,fts) into pts
            
            if fts is "65" then
               --breakpoint
            end if
            
            put byte 21 to 22 of tChunk into tfnum
            put binaryDecode("m",tfnum,fnum) into pfnum
            
            put byte 23 to 24 of tChunk into tdnum
            put binaryDecode("m",tdnum,dnum) into pdnum
            break
      end switch
      if tcounter >= 1000 then
         exit repeat
      end if
   end repeat
   breakpoint
   --$signature . $header . $parts[$i] . $end; 
   put tSig & tHeader & tPic & tIEND into sPic
   set the text of img "test3" to sPic --into img "test3"
   
   put specialfolderpath("desktop") & "/image.png" into theFilepath
   open file theFilepath for binary write ## you might also use 'binary update' here to modify part of file
   write sPic to file theFilePath
   close file theFilePath 
   end mouseup 
Ref image:

Image
Last edited by istech on Sun Jan 31, 2021 1:53 pm, edited 1 time in total.

richmond62
Livecode Opensource Backer
Livecode Opensource Backer
Posts: 9386
Joined: Fri Feb 19, 2010 10:17 am
Location: Bulgaria

Re: Fun With APNG & LC

Post by richmond62 » Fri Jan 29, 2021 7:51 pm

Well, what to one person might be an idea of fun seems to another rather a waste of time
as LiveCode can cope with animated GIF images as well as present animations in quite a few
ways without havint to worry about what seems a format that is a real case of
"a coming man already gone".

I wonder if anyone other than Thee knew what an APNG was off the top of their head,
and whether, like MNG, anybody in interested at all . . .

We could also discuss 8-track cassettes, Betamax video cassettes, Video disks, those
wierd CDs containing movies in an odd format from Taiwan I used to buy under the counter
in Sharjah in 1989, and so.

istech
Posts: 194
Joined: Thu Sep 19, 2013 10:08 am

Re: Fun With APNG & LC

Post by istech » Fri Jan 29, 2021 9:14 pm

We could also discuss 8-track cassettes, Betamax video cassettes, Video disks, those
wierd CDs containing movies in an odd format from Taiwan I used to buy under the counter
in Sharjah in 1989, and so.
I like this one and can help make my point.

GIF = VHS Tapes

APNG = Betamax

Betamax was always the better format but VHS won in the end because of adoption.

I also like to try new things with LC to grow my understanding of commands and functions I have not tried before. In doing so I find it fun.....sometimes. :D

But APNG has always been a hobby of mine as I detest GIFs in everyway, especially in LC. I work a lot with UI's and having an APNG to just pop in and play would save me some time.

Maybe it's just me. :)

dunbarx
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 9663
Joined: Wed May 06, 2009 2:28 pm
Location: New York, NY

Re: Fun With APNG & LC

Post by dunbarx » Fri Jan 29, 2021 11:14 pm

Maybe it's just me. :)
It is not just you.

I am fond of telling new users, learning the very basics of LC, to make a stack of any kind. An address book, a calculator, whatever, likely to be utterly useless once they become more proficient.

It is the exercise, the actual work that matters, not whether the tools are old or any possible outcome is going to be useful.

Do it. Write back with your progress, problems and thoughts.

Craig

richmond62
Livecode Opensource Backer
Livecode Opensource Backer
Posts: 9386
Joined: Fri Feb 19, 2010 10:17 am
Location: Bulgaria

Re: Fun With APNG & LC

Post by richmond62 » Sat Jan 30, 2021 11:55 am

VHS won in the end because of adoption
Well, yes, VHS came in like a changeling dumped by the fairies.

And, certainly, as a mental exercise there is absolutely nothing wrong with "exorcising"
ghosts with LiveCode (and probably beats Bell, Book and Candle).

Personally, a start here might not be such a bad idea:

http://littlesvr.ca/apng/samples.html

What seems odd to me is that if one downloads one of those sample APNG images they come down
with the .png suffix, but then, when opened they show multiple frames, almost exactly like a .gif image.
-
o_sample.png
o_sample.png (112.95 KiB) Viewed 7184 times
-
But, on import into a LiveCode stack ONLY the first frame is displayed, so there is no animation effect.

richmond62
Livecode Opensource Backer
Livecode Opensource Backer
Posts: 9386
Joined: Fri Feb 19, 2010 10:17 am
Location: Bulgaria

Re: Fun With APNG & LC

Post by richmond62 » Sat Jan 30, 2021 12:52 pm

No frameCount is reported.

Code: Select all

on mouseUp
   put the frameCount of img "o_sample.png"
end mouseUp
Preview (macOS 11.1) shows 6 frames. GIMP shows no frames at all. Krita does no better.

richmond62
Livecode Opensource Backer
Livecode Opensource Backer
Posts: 9386
Joined: Fri Feb 19, 2010 10:17 am
Location: Bulgaria

Re: Fun With APNG & LC

Post by richmond62 » Sat Jan 30, 2021 2:05 pm


istech
Posts: 194
Joined: Thu Sep 19, 2013 10:08 am

Re: Fun With APNG & LC

Post by istech » Sun Jan 31, 2021 1:05 pm

The idea is to extract the frames from an APNG image when imported into a Livecode img control. The APNG files act very similar to a gif and have a .png extension. The frames are imbedded into the image. See the image below. I'm about 90% there. But there is still some issues with the corrupted frames. Just need to work out why they are coming out corrupted when exported. Could be multiple reasons in respect to the png specification, most likely the files exported are not valid png file formats. Looking at the crc calculation and the png file exported to see what's wrong. Could be I'm not calculating the crc properly for the whole png file before export. We will see. :D

Image

more spec details below.

APNG File Format
APNG files are stored as binary files on disc and use the extended specifications of PNG for animated images. The first frame of an APNG file is a normal PNG stream that is readable by PNG decoders for display. APNG file format follow the PNG specifications and data is stored in segments called chunks. However, APNG introduced the following new chunks:

Animation Control Chunk (acTL) - Indicates that this file is an animated PNG file rather than a normal PNG file. It acts as a marker and comes before the IDAT chunk. It also contains the number of frames and information about times to loop the animations

Frame Control Chunk - Occurs at start of each and metadata information such as dimensions, position, transparency application, and replacement information by previous or next frame once it is over.

Frame Data Chunk - Stores frame’s contents and starts with a sequence number. This sequence number has the same structure as the default image’s IDAT chunk.

Animated PNG - APNG File Format
APNG is backward compatible with PNG as the lateral’s specifications were designed in such a way that an application reading a PNG file is supposed to simply ignore the chunks which it does not understand. Specifications regarding bit depth, color type, compression, filters, interlace methods, and palette information are used the same as that of default PNG format.

richmond62
Livecode Opensource Backer
Livecode Opensource Backer
Posts: 9386
Joined: Fri Feb 19, 2010 10:17 am
Location: Bulgaria

Re: Fun With APNG & LC

Post by richmond62 » Sun Jan 31, 2021 3:24 pm

Screenshot 2021-01-31 at 16.22.55.png
-
If one opens an APNG image using a text editor (I used BBEdit) the fcTL starts of each frame show up clearly.

richmond62
Livecode Opensource Backer
Livecode Opensource Backer
Posts: 9386
Joined: Fri Feb 19, 2010 10:17 am
Location: Bulgaria

Re: Fun With APNG & LC

Post by richmond62 » Sun Jan 31, 2021 3:37 pm

Screenshot 2021-01-31 at 16.35.51.png
-
I have started by importing an APNG image and putting it as text into a field.

Code: Select all

on mouseUp
   set the ink of me to srcCopy
   answer file "Choose an APNG file to import"
   if the result = "cancel" 
   then exit mouseUp
   else
      set the text of fld "PICC" to URL ("file:" & it)
   end if
end mouseUp

richmond62
Livecode Opensource Backer
Livecode Opensource Backer
Posts: 9386
Joined: Fri Feb 19, 2010 10:17 am
Location: Bulgaria

Re: Fun With APNG & LC

Post by richmond62 » Sun Jan 31, 2021 5:51 pm

The idea that the acTL section contains the number of frames of an APNG is a bit difficult to understand.

In my example (above) acLT contains 5∞, while the image consists of 6 frames.

"elephant" acTL contains 2Lºt , while the image consists of 34 frames.

kdjanz
Posts: 300
Joined: Fri Dec 09, 2011 12:12 pm
Location: Fort Saskatchewan, AB Canada

Re: Fun With APNG & LC

Post by kdjanz » Mon Feb 01, 2021 3:59 am

You’re working in binary file, so what do those bytes mean when interpreted as a decimal integer?

SparkOut
Posts: 2852
Joined: Sun Sep 23, 2007 4:58 pm

Re: Fun With APNG & LC

Post by SparkOut » Mon Feb 01, 2021 8:32 am

And not that I have a chance to play with this too, but don't forget the import will need to use "binfile:" not "file:" in the url.

istech
Posts: 194
Joined: Thu Sep 19, 2013 10:08 am

Re: Fun With APNG & LC

Post by istech » Tue Feb 02, 2021 6:24 pm

To explain the process at little better take a look at this diagram. It may help understand where I'm going with this.

I believe now I'm on the final hurdle. The creation of the new hash based on crc32b() is the only hold up. I don't think Livecode have a function for it. I found on the forums a crc32() function floating around. However, the crc32() hash generated is different to crc32b(). So either a kind sole has a crc32b() hashing function or I need to look at the spec and create one from the crc32() one I already have.

The Livecode equivalent of the php command " $chunk .= hash('crc32b',$type.$chunk,true);"

[EDIT] I've now found a livecode crc32() function that is giving me what I need. So great! fingers crossed. "http://at.livecodejournal.com/stacks/CRC-32.rev"

Never the less still having fun with it. :D
Attachments
unnamed.png

capellan
Posts: 654
Joined: Wed Aug 15, 2007 11:09 pm

Re: Fun With APNG & LC

Post by capellan » Wed Feb 10, 2021 1:43 am

Hi Istech,

According to this webpage https://github.com/Michaelangel007/crc32
the stack produces a hash for crc32b.

In fact, I posted this stack long, long time ago, and back then discovered that
hashing some kind of data produces wrong results.

Using the crc32b produced by the built-in Livecode function "compress"
is more reliable.


Screen Shot 2021-02-09 at 8.31.05 PM.png

Post Reply

Return to “Talking LiveCode”