Changes between Initial Version and Version 1 of Develop/FileFormats/PKM


Ignore:
Timestamp:
Oct 8, 2016, 1:33:42 PM (8 years ago)
Author:
pulkomandy
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • Develop/FileFormats/PKM

    v1 v1  
     1= The PKM picture format - by Karl Maritaud =
     2
     3First of all, I'd like to say that I made this file format some years ago when I didn't knew how to load any good format (eg. GIF) and wanted to have my own format.
     4PKM format was designed to be very simple, easy to encode and decode. Its header is very simple (short) and evolutive.
     5The only real default I can find in this format is that you can only save 256-color pictures.
     6I know that you will think:
     7"Oh no just another fucking format! I'll never use it! Its compression is too poor and I prefer GIF!".
     8And I'll answer:
     9"Yeah! You're right. But if you dunno how to load GIF and want a simple format with a quite good compression rate (on simple pictures at least), it could be useful."
     10
     11So, here comes the format documentation...
     12
     13
     14= The HEADER: =
     15
     16The header is the following 780-byte-structure. (Don't worry about the size.
     17That's just because the palette is considered as a part of the header).
     18
     19|| Pos || Field || Type || Size || Description ||
     20|| 0 || Signature || char || 3 || Constant string "PKM" (with NO size delimitation '\0' or so...) ||
     21|| 3 || Version || byte || 1 || For the moment, it can take only the  value 0. Other packing methods may change this field but there is only one for now... ||
     22|| 4 || Pack_byte || byte || 1 || Value of the recognition byte for color repetitions that are coded on 1 byte. (See the picture packing section for a better explanation) ||
     23|| 5 || Pack_word || byte || 1 || Value of the recognition byte for color repetitions that are coded on 2 bytes. (See the picture packing section...) ||
     24|| 6 || Width || word || 2 || Picture width  (in pixels) ||
     25|| 8 || Height || word || 2 || Picture height (in pixels) ||
     26|| 10 || Palette || byte || 768 || RGB palette (RGB RGB ... 256 times) with values from 0 to 63. I know the standard in picture files is 0 to 255 but I find it stupid! It is really easier to send the whole palette in port 3C9h with a REP OUTSB without palette convertion. ||
     27|| 778 || PH_size || word || 2 || Post-header size. This is the number of bytes between the header and the picture data. This value can be equal to 0. ||
     28
     29= The POST-HEADER: =
     30
     31  The post-header has a variable size. It was designed to support new features
     32for this file format without changing the whole format.
     33
     34  It consists in field identifiers followed by their size and their value.
     35  A field identifier is coded with 1 byte and a field size also.
     36
     37
     38== These field identifiers are: ==
     39
     40(this list may be updated...)
     41
     42    0 : Comment on the picture
     43    1 : Original screen dimensions
     44    2 : Back color (transparent color)
     45
     46  If you encounter a field that you don't know just jump over it. But if a
     47  field tells you to jump to a position that is over the beginning of the
     48  picture data, there is an error in the file.
     49
     50
     51== The fields: ==
     52
     53    * Comment:
     54
     55      With this field, artists will be able to comment their pictures.
     56      Note that GrafX 2 has a comment size limit of 32 chars. But you can
     57      comment a picture with up to 255 chars if you make your own viewer
     58      since GrafX 2 will just ignore extra characters.
     59
     60      Example: [0],[16],[Picture by X-Man]
     61      This sequence means:
     62        - the field is a comment
     63        - the comment takes 16 characters (there is no end-of-string character
     64          since you know its size)
     65        - the comment is "Picture by X-Man"
     66
     67    * Original screen dimensions:
     68
     69      Since GrafX 2 supplies a huge range of resolutions, it seemed convenient
     70      to add a field that indicates what were the original screen dimensions.
     71
     72      Example: [1],[4],[320],[256]
     73      This sequence means:
     74        - the field is a screen dimensions descriptor
     75        - the dimensions are 2 words (so this value must be always equal to 4)
     76        - the original screen width was 320 pixels
     77        - the original screen height was 256 pixels
     78
     79      Note that words stored in fields are written Intel-like. The 90% BETA
     80      version did not respect this norm. I'm really sorry about this. This is
     81      not very serious but pictures saved with version 90% and loaded with a
     82      latest version (91% and more) won't set the right resolution.
     83
     84    * Back color:
     85
     86      Saving the back color (transparent color) is especially useful when you
     87      want to save a brush.
     88      The size of this field is 1 byte (index of the color between 0 and 255).
     89
     90      Example: [2],[1],[255]
     91      This sequence means:
     92        - the field is a screen dimensions descriptor
     93        - the value takes 1 byte
     94        - the transparent color is 255
     95
     96
     97= The PICTURE PACKING METHOD: =
     98
     99  The PKM compression method is some sort of Run-Length-Compression which is
     100very efficient on pictures with long horizontal color repetitions.
     101  Actually, the compression is efficient if there are often more than 3 times
     102the same color consecutively.
     103
     104  I think that it would be better to give you the algorithm instead of swim-
     105ming in incomprehensible explanations.
     106
     107{{{
     108  BEGIN
     109    /*
     110      functions:
     111        Read_byte(File)       reads and returns 1 byte from File
     112        Draw_pixel(X,Y,Color) draws a pixel of a certain Color at pos. (X,Y)
     113        File_length(File)     returns the total length in bytes of File
     114
     115      variables:
     116        type of Image_size          is dword
     117        type of Data_size           is dword
     118        type of Packed_data_counter is dword
     119        type of Pixels_counter      is dword
     120        type of Color               is byte
     121        type of Byte_read           is byte
     122        type of Word_read           is word
     123        type of Counter             is word
     124        type of File                is <binary file>
     125    */
     126
     127    /* At this point you've already read the header and post-header. */
     128
     129    Image_size          <- Header.Width * Header.Height
     130    Data_size           <- File_length(File) - (780+Header.PH_size)
     131
     132    Packed_data_counter <- 0
     133    Pixels_counter      <- 0
     134
     135    /* Depacking loop: */
     136    WHILE ((Pixels_counter<Image_size) AND (Packed_data_counter<Data_size)) DO
     137    {
     138      Byte_read <- Read_byte(File)
     139
     140      /* If it is not a packet recognizer, it's a raw pixel */
     141      IF ((Byte_read<>Header.Pack_byte) AND (Byte_read<>Header.Pack_word))
     142      THEN
     143      {
     144        Draw_pixel(Pixels_counter MOD Header.Width,
     145                   Pixels_counter DIV Header.Width,
     146                   Byte_read)
     147
     148        Pixels_counter      <- Pixels_counter + 1
     149        Packed_data_counter <- Packed_data_counter + 1
     150      }
     151      ELSE /* Is the number of pixels to repeat coded... */
     152      {    /* ... with 1 byte */
     153        IF (Byte_read = Header.Pack_byte) THEN
     154        {
     155          Color     <- Read_byte(File)
     156          Byte_read <- Read_byte(File)
     157
     158          FOR Counter FROM 0 TO (Byte_read-1) STEP +1
     159            Draw_pixel((Pixels_counter+Counter) MOD Header.Width,
     160                       (Pixels_counter+Counter) DIV Header.Width,
     161                       Color)
     162
     163          Pixels_counter      <- Pixels_counter + Byte_read
     164          Packed_data_counter <- Packed_data_counter + 3
     165        }
     166        ELSE /* ... with 2 bytes */
     167        {
     168          Color     <- Read_byte(File)
     169          Word_read <- (word value) (Read_byte(File) SHL 8)+Read_byte(File)
     170
     171          FOR Counter FROM 0 TO (Word_read-1) STEP +1
     172            Draw_pixel((Pixels_counter+Counter) MOD Header.Width,
     173                       (Pixels_counter+Counter) DIV Header.Width,
     174                       Color)
     175
     176          Pixels_counter      <- Pixels_counter + Word_read
     177          Packed_data_counter <- Packed_data_counter + 4
     178        }
     179      }
     180    }
     181  END
     182}}}
     183
     184  For example, the following sequence:
     185    (we suppose that Pack_byte=01 and Pack_word=02)
     186    04 03 01 05 06 03 02 00 01 2C
     187  will be decoded as:
     188    04 03 05 05 05 05 05 05 03 00 00 00 ... (repeat 0 300 times (012Ch=300))
     189
     190  Repetitions that fit in a word must be written with their higher byte first.
     191  I know that it goes against Intel standard but since I read bytes from the
     192  file thru a buffer (really faster), I don't care about the order (Sorry :)).
     193  But words in the header and post-header must be written and read Intel-like!
     194
     195
     196== Packing advices: ==
     197
     198  * As you can see, there could be a problem when you'd want to pack a raw
     199  pixel with a color equal to Pack_byte or Pack_word. These pixels should
     200  always be coded as a packet even if there is only one pixel.
     201
     202    Example: (we suppose that Pack_byte=9)
     203      9   will be encoded 9,9,1     (The 1st 9 in the encoded...
     204      9,9 will be encoded 9,9,2     ... sequence is Pack_byte)
     205      etc...
     206
     207  * It seems obvious to find values for Pack_byte and Pack_word that are
     208  (almost) never used. So a small routine that finds the 2 less used colors
     209  in the image should be called before starting to pack the picture. This can
     210  be done almost instantaneously in Assembler.
     211
     212  * When you want to pack a 2-color-sequence, just write these 2 colors one
     213  after the other (Color,Color) because it only takes 2 bytes instead of 3 if
     214  you had to write a packet (Pack_byte,Color,2).
     215
     216  * If you pack a very simple picture which has a sequence of more than 65535
     217  same consecutive bytes, you must break the sequence and continue with a new
     218  packet.
     219
     220    Example: you have to pack 65635 same consecutive bytes (eg. color 0)
     221      (we suppose that Pack_byte=01 and Pack_word=02)
     222      You'll write: 02 00 FF FF 01 00 64        (FFFFh=65535, 64h=100)