fortran66のブログ

fortran について書きます。

【メモ帳】gif 画像出力

アニメ gif が作りたくなって

なんとなくアニメ gif が出来るとうれしいなと思い立って、少し調べてみました。

以下のサイト、およびそこからリンクされているサイトをアニメを見ながら眺めること1時間。
最小サイズのgif画像とアニメーションgif – ソフトウェア開発日記

どうもデータ長を 8bit にすると、バイト単位で扱えるようになって楽な気がしたので実験してみることにしてみました。まずは静的な画像から。

実行結果

f:id:fortran66:20180421015217g:plain
f:id:fortran66:20180421014645g:plain

ソースプログラム

    program gif
      use, intrinsic :: iso_fortran_env 
      implicit none
      integer :: iw
      integer(int16) :: m, nx = 15, ny = 10
      type :: t_gif_header
        sequence  
        character(3) :: signature = 'GIF'
        character(3) :: version   = '89a' ! '87a'
        integer(int16) :: width
        integer(int16) :: height 
        integer(int8)  :: pck   = int(B'10001001', int8) 
        integer(int8)  :: background_color_index = 0
        integer(int8)  :: pixel_aspect_ratio     = 0
      end type  
      integer(int8), allocatable :: global_color_table(:)
      type (t_gif_header) :: head
      
      type :: t_image_block
        sequence
        integer(int8) :: image_separator = Z'2C'
        integer(int16) :: image_left_position = 00
        integer(int16) :: image_top_position  = 00
        integer(int16) :: image_width 
        integer(int16) :: image_height
        integer(int8) :: pck = int(B'00000000', int8)
        ! local color table
        !integer(int8) :: LZW_minimum_code_size 
        !integer(int8) :: block_size = 
        !integer(int8) :: image_data
        !integer(int8) :: block_terminator = Z'00'  
      end type t_image_block
      type (t_image_block) :: img    
      integer, allocatable :: ipattern(:)
!
!      open(newunit = iw, file = 'test.bin', access = 'stream')
      open(newunit = iw, file = 'test.gif', access = 'stream')
      head%width  = nx
      head%height = ny
      img%image_width  = nx
      img%image_height = ny
!      
      allocate(global_color_table(3 * 128)) ! 128?
      global_color_table = 0
      global_color_table = int([0,0,0,255, 0, 0, 0,255,0, 0,0,255], int8) ! RGB
      write(iw) head      
      write(iw) global_color_table
!
      ipattern = [01, 01, 01, 01, 01, 02, 02, 02, 02, 02, 03, 03, 03, 03, 03] ! RGB
!
      write(iw) img     
      write(iw) achar([07, 152])            ! 7+1 bit ~ 128 color, 152 data (150 RGB + 2 clear)
      write(iw) achar([ipattern, ipattern])
      write(iw) achar([ipattern, ipattern])
      write(iw) achar([ipattern, ipattern])
      write(iw) achar([ipattern, ipattern])
      write(iw) achar([128]) ! clear dictionary ?
      write(iw) achar([ipattern, ipattern])
      write(iw) achar([128]) ! clear dictionary ?
      write(iw) achar(00) ! block_terminator
      write(iw) achar(int(Z'3B'))    
    end program gif

データ 4bit 単位 8色

データ単位が 4bit なら2ピクセルで 1byte になるので分かりやすいはず。

実行結果

f:id:fortran66:20180421124217g:plain
f:id:fortran66:20180421124745p:plain

ソースプログラム

バイト内のオーダーが逆っぽいのが謎??勘違いしている?下位ビットから読む?

    program gif
      use, intrinsic :: iso_fortran_env 
      implicit none
      integer :: iw
      integer(int16) :: m, nx = 10, ny = 10
      type :: t_gif_header
        sequence  
        character(3) :: signature = 'GIF'
        character(3) :: version   = '89a' ! '87a'
        integer(int16) :: width
        integer(int16) :: height 
        integer(int8)  :: pck   = int(B'10001001', int8) 
        integer(int8)  :: background_color_index = 0
        integer(int8)  :: pixel_aspect_ratio     = 0
      end type  
      integer(int8), allocatable :: global_color_table(:)
      type (t_gif_header) :: head
      
      type :: t_image_block
        sequence
        integer(int8) :: image_separator = Z'2C'
        integer(int16) :: image_left_position = 00
        integer(int16) :: image_top_position  = 00
        integer(int16) :: image_width 
        integer(int16) :: image_height
        integer(int8) :: pck = int(B'00000000', int8)
        ! local color table
      end type t_image_block
      type (t_image_block) :: img    
!
      open(newunit = iw, file = 'test.gif', access = 'stream')
      head%width  = nx
      head%height = ny
      img%image_width  = nx
      img%image_height = ny
!      
      allocate(global_color_table(3 * 8)) ! 8?
      global_color_table = 0
      global_color_table = int([0,0,0,255, 0, 0, 0,255,0, 0,0,255], int8) ! RGB
      write(iw) head      
      write(iw) global_color_table
!
      write(iw) img     
      write(iw) achar([03, 60])            ! 3+1 bit ~ 8 color, 60 byte (100 RGB + 20 clear)
      write(iw) achar([Z'21', Z'13', Z'32', Z'18', Z'32', Z'81'])
      write(iw) achar([Z'21', Z'13', Z'32', Z'18', Z'32', Z'81'])
      write(iw) achar([Z'21', Z'13', Z'32', Z'18', Z'32', Z'81'])
      write(iw) achar([Z'21', Z'13', Z'32', Z'18', Z'32', Z'81'])
      write(iw) achar([Z'21', Z'13', Z'32', Z'18', Z'32', Z'81'])
      write(iw) achar([Z'21', Z'13', Z'32', Z'18', Z'32', Z'81'])
      write(iw) achar([Z'21', Z'13', Z'32', Z'18', Z'32', Z'81'])
      write(iw) achar([Z'21', Z'13', Z'32', Z'18', Z'32', Z'81'])
      write(iw) achar([Z'21', Z'13', Z'32', Z'18', Z'32', Z'81'])
      write(iw) achar([Z'21', Z'13', Z'32', Z'18', Z'32', Z'81'])
      write(iw) achar(00) ! block_terminator
      write(iw) achar(int(Z'3B'))    
    end program gif