PKM format

Ideas for improvements and requests for new features in XnView Classic

Moderators: helmut, XnTriq, xnview

Post Reply
User avatar
Jaff
Posts: 67
Joined: Fri Dec 07, 2007 8:55 am
Location: Romania
Contact:

PKM format

Post by Jaff »

I would like to open/save in PKM image format too. Here's GrafX 2.00 Beta 96.5% (the freeware program who use and created this file format)

!WARNING! instead of 0..255 (888) it uses values from 0..63 (555)

Here is the file format from the doc's:
The PKM picture format - by Karl Maritaud

First 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.
PKM format was designed to be very simple, easy to encode and decode. Its header is very simple (short) and evolutive.
The only real default I can find in this format is that you can only save 256-color pictures.
I know that you will think:
"Oh no just another fucking format! I'll never use it! Its compression is too poor and I prefer GIF!".
And I'll answer:
"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."

So, here comes the format documentation...


The HEADER:

The header is the following 780-byte-structure. (Don't worry about the size.
That's just because the palette is considered as a part of the header).

Code: Select all

┌─────┬───────────┬──────┬──────┬──────────────────────────────────────────┐
│ Pos │ Field     │ Type │ Size │ Description                              │
?═════?═══════════?══════?══════?══════════════════════════════════════════?
│   0 │ Signature │ char │   3  │ Constant string "PKM" (with NO size      │
│     │           │      │      │ delimitation '\0' or so...)              │
├─────┼───────────┼──────┼──────┼──────────────────────────────────────────┤
│   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...   │
├─────┼───────────┼──────┼──────┼──────────────────────────────────────────┤
│   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)                      │
├─────┼───────────┼──────┼──────┼──────────────────────────────────────────┤
│   5 │ Pack_word │ byte │   1  │ Value of the recognition byte for color  │
│     │           │      │      │ repetitions that are coded on 2 bytes.   │
│     │           │      │      │ (See the picture packing section...)     │
├─────┼───────────┼──────┼──────┼──────────────────────────────────────────┤
│   6 │ Width     │ word │   2  │ Picture width  (in pixels)               │
├─────┼───────────┼──────┼──────┼──────────────────────────────────────────┤
│   8 │ Height    │ word │   2  │ Picture height (in pixels)               │
├─────┼───────────┼──────┼──────┼──────────────────────────────────────────┤
│  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.    │
├─────┼───────────┼──────┼──────┼──────────────────────────────────────────┤
│ 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.      │
└─────┴───────────┴──────┴──────┴──────────────────────────────────────────┘
Data of type "word" are stored with Intel conventions: lower byte first.

The POST-HEADER:

The post-header has a variable size. It was designed to support new features for this file format without changing the whole format.

It consists in field identifiers followed by their size and their value.
A field identifier is coded with 1 byte and a field size also.


These field identifiers are: (this list may be updated...)

0 : Comment on the picture
1 : Original screen dimensions
2 : Back color (transparent color)

If you encounter a field that you don't know just jump over it. But if a field tells you to jump to a position that is over the beginning of the picture data, there is an error in the file.

The fields:
  • Comment:
    With this field, artists will be able to comment their pictures.
    Note that GrafX 2 has a comment size limit of 32 chars. But you can comment a picture with up to 255 chars if you make your own viewer since GrafX 2 will just ignore extra characters.

    Example: [0],[16],[Picture by X-Man]
    This sequence means:
    - the field is a comment
    - the comment takes 16 characters (there is no end-of-string character since you know its size)
    - the comment is "Picture by X-Man"
  • Original screen dimensions:
    Since GrafX 2 supplies a huge range of resolutions, it seemed convenient to add a field that indicates what were the original screen dimensions.

    Example: [1],[4],[320],[256]
    This sequence means:
    - the field is a screen dimensions descriptor
    - the dimensions are 2 words (so this value must be always equal to 4)
    - the original screen width was 320 pixels
    - the original screen height was 256 pixels

    Note that words stored in fields are written Intel-like. The 90% BETA version did not respect this norm. I'm really sorry about this. This is not very serious but pictures saved with version 90% and loaded with a latest version (91% and more) won't set the right resolution.
  • Back color:
    Saving the back color (transparent color) is especially useful when you want to save a brush.
    The size of this field is 1 byte (index of the color between 0 and 255).

    Example: [2],[1],[255]
    This sequence means:
    - the field is a screen dimensions descriptor
    - the value takes 1 byte
    - the transparent color is 255

The PICTURE PACKING METHOD:

The PKM compression method is some sort of Run-Length-Compression which is very efficient on pictures with long horizontal color repetitions.
Actually, the compression is efficient if there are often more than 3 times the same color consecutively.

I think that it would be better to give you the algorithm instead of swimming in incomprehensible explanations.

Code: Select all

BEGIN
  /*
    functions:
      Read_byte(File)       reads and returns 1 byte from File
      Draw_pixel(X,Y,Color) draws a pixel of a certain Color at pos. (X,Y)
      File_length(File)     returns the total length in bytes of File

    variables:
      type of Image_size          is dword
      type of Data_size           is dword
      type of Packed_data_counter is dword
      type of Pixels_counter      is dword
      type of Color               is byte
      type of Byte_read           is byte
      type of Word_read           is word
      type of Counter             is word
      type of File                is <binary>
  */

  /* At this point you've already read the header and post-header. */

  Image_size          <- Header.Width * Header.Height
  Data_size           <- File_length(File) - (780+Header.PH_size)

  Packed_data_counter <- 0
  Pixels_counter      <- 0

  /* Depacking loop: */
  WHILE ((Pixels_counter<Image_size) AND (Packed_data_counter<Data_size)) DO
  {
    Byte_read <- Read_byte(File)

    /* If it is not a packet recognizer, it's a raw pixel */
    IF ((Byte_read<>Header.Pack_byte) AND (Byte_read<>Header.Pack_word))
    THEN
    {
      Draw_pixel(Pixels_counter MOD Header.Width,
                 Pixels_counter DIV Header.Width,
                 Byte_read)

      Pixels_counter      <- Pixels_counter + 1
      Packed_data_counter <- Packed_data_counter + 1
    }
    ELSE /* Is the number of pixels to repeat coded... */
    {    /* ... with 1 byte */
      IF (Byte_read = Header.Pack_byte) THEN
      {
        Color     <- Read_byte(File)
        Byte_read <- Read_byte(File)

        FOR Counter FROM 0 TO (Byte_read-1) STEP +1
          Draw_pixel((Pixels_counter+Counter) MOD Header.Width,
                     (Pixels_counter+Counter) DIV Header.Width,
                     Color)

        Pixels_counter      <- Pixels_counter + Byte_read
        Packed_data_counter <- Packed_data_counter + 3
      }
      ELSE /* ... with 2 bytes */
      {
        Color     <- Read_byte(File)
        Word_read <- (word value) (Read_byte(File) SHL 8)+Read_byte(File)

        FOR Counter FROM 0 TO (Word_read-1) STEP +1
          Draw_pixel((Pixels_counter+Counter) MOD Header.Width,
                     (Pixels_counter+Counter) DIV Header.Width,
                     Color)

        Pixels_counter      <- Pixels_counter + Word_read
        Packed_data_counter <- Packed_data_counter + 4
      }
    }
  }
END
For example, the following sequence:
(we suppose that Pack_byte=01 and Pack_word=02)
04 03 01 05 06 03 02 00 01 2C
will be decoded as:
04 03 05 05 05 05 05 05 03 00 00 00 ... (repeat 0 300 times (012Ch=300))

Repetitions that fit in a word must be written with their higher byte first.
I know that it goes against Intel standard but since I read bytes from the file thru a buffer (really faster), I don't care about the order (Sorry :)).
But words in the header and post-header must be written and read Intel-like!


Packing advices:
  • As you can see, there could be a problem when you'd want to pack a raw pixel with a color equal to Pack_byte or Pack_word. These pixels should always be coded as a packet even if there is only one pixel.

    Example: (we suppose that Pack_byte=9)
    9 will be encoded 9,9,1 (The 1st 9 in the encoded...
    9,9 will be encoded 9,9,2 ... sequence is Pack_byte)
    etc...
  • It seems obvious to find values for Pack_byte and Pack_word that are (almost) never used. So a small routine that finds the 2 less used colors in the image should be called before starting to pack the picture. This can be done almost instantaneously in Assembler.
  • When you want to pack a 2-color-sequence, just write these 2 colors one after the other (Color,Color) because it only takes 2 bytes instead of 3 if you had to write a packet (Pack_byte,Color,2).
  • If you pack a very simple picture which has a sequence of more than 65535 same consecutive bytes, you must break the sequence and continue with a new packet.
Example: you have to pack 65635 same consecutive bytes (eg. color 0)
(we suppose that Pack_byte=01 and Pack_word=02)
You'll write: 02 00 FF FF 01 00 64 (FFFFh=65535, 64h=100)
Imi este indiferent ce cred ceilalti despre mine, caci oricum fiecare crede ce-i convine lui si nu ceea ce e real, doar ca mi-ar fi placut sa ma vada asa cum sint de fapt, nu asa cum poate le-ar placea lor sa creada. Ei au ales deja...
User avatar
xnview
Author of XnView
Posts: 46255
Joined: Mon Oct 13, 2003 7:31 am
Location: France
Contact:

Re: PKM format

Post by xnview »

Is it possible to send some picture samples? I have a crash of the program.
Pierre.
User avatar
Jaff
Posts: 67
Joined: Fri Dec 07, 2007 8:55 am
Location: Romania
Contact:

some samples

Post by Jaff »

Here are the images included in package saved with GFX2 in PKM format plus TEST.PKM and TEST2.PKM.
TEST.PKM is a converted file saved with my Screen Convertor (tool for converting from/to screen$ format used by ZX-Spectrum computers and later by emulators on PC). This file is uncompressed! Yes, it's possible if you have at least 2 unused colors. I use #FE and #FF as markers, colors unused in image :P
TEST2.PKM is my file saved by GFX2 (compressed format)
Imi este indiferent ce cred ceilalti despre mine, caci oricum fiecare crede ce-i convine lui si nu ceea ce e real, doar ca mi-ar fi placut sa ma vada asa cum sint de fapt, nu asa cum poate le-ar placea lor sa creada. Ei au ales deja...
User avatar
Karl02
Posts: 134
Joined: Mon Sep 03, 2007 1:00 pm
Location: Germany

Post by Karl02 »

This would be a way to increase the number of supported file formats, but I fear that for more than 99.999 % of all XnView users this feature will be completely useless. I would suggest to write a special converter to convert this file format to a standard format, not use it for saving new images and then forget it. :?
-- Karl
User avatar
Clo
XnThusiast
Posts: 4441
Joined: Sun Oct 17, 2004 4:57 am
Location: Bordeaux, France
Contact:

Wise---

Post by Clo »

:arrow: Karl02

:) Hello !
…I would suggest to write a special converter to convert this file format to a standard format,
not use it for saving new images and then forget it. :?
• Wise advice, I support !

- A converter, maybe, if that's not too time-consuming for Pierre
- IMHO, he has other fish to fry (and especially prepare the languages as text before my funeral !) :P

:mrgreen: VG
Claude
Clo
Old user ON SELECTIVE STRIKE till further notice
User avatar
Jaff
Posts: 67
Joined: Fri Dec 07, 2007 8:55 am
Location: Romania
Contact:

Post by Jaff »

Karl02 wrote:This would be a way to increase the number of supported file formats, but I fear that for more than 99.999 % of all XnView users this feature will be completely useless. I would suggest to write a special converter to convert this file format to a standard format, not use it for saving new images and then forget it. :?
Hmm...
1) Why write an convertor when GrafX2 can open & write his own PKM images as BMP/GIF/LBM/PCX? I've wanted XnView were able to open this kind of images.
2) for 99.999% of all XnView users shuld support only BMP/JPG/GIF/PNG formats. This will make XnView faster and smaller, right? :D
Imi este indiferent ce cred ceilalti despre mine, caci oricum fiecare crede ce-i convine lui si nu ceea ce e real, doar ca mi-ar fi placut sa ma vada asa cum sint de fapt, nu asa cum poate le-ar placea lor sa creada. Ei au ales deja...
User avatar
helmut
Posts: 8704
Joined: Sun Oct 12, 2003 6:47 pm
Location: Frankfurt, Germany

Post by helmut »

A strength of XnView is the numer of file formats supported. So I think it would be good to add the PKM format.

But:
Adding a specific file format should depend on
a.) effort for development and integration
b.) number of users of this format
c.) number of image files available in this format (e.g. in the web)

And there are various levels of integration:
A.) integration in download package "Standard"
B.) integration in download package "Complete"
C.) direct download of the plug-in, only. (not included in any XnView download package).

I'm not sure what answers a.)-c.) are for the PKM format. Depending on the answers a.)-c.) and the file size of the PKM DLL (which has impact on the download size of the XnView package), one of the integration levels A.) - C.) should be chosen.

So:
Inlcuding the PKM format is a good idea, but the above aspects should be taken into account.
User avatar
Jaff
Posts: 67
Joined: Fri Dec 07, 2007 8:55 am
Location: Romania
Contact:

Post by Jaff »

Since PKM format is a rare one, I chose C.
Imi este indiferent ce cred ceilalti despre mine, caci oricum fiecare crede ce-i convine lui si nu ceea ce e real, doar ca mi-ar fi placut sa ma vada asa cum sint de fapt, nu asa cum poate le-ar placea lor sa creada. Ei au ales deja...
User avatar
Karl02
Posts: 134
Joined: Mon Sep 03, 2007 1:00 pm
Location: Germany

Post by Karl02 »

One question: Would it actually be possible e.g. for Jaff or other contributors to write (and maintain) a separate plug-in for his file format himself?
-- Karl
User avatar
xnview
Author of XnView
Posts: 46255
Joined: Mon Oct 13, 2003 7:31 am
Location: France
Contact:

Post by xnview »

Karl02 wrote:One question: Would it actually be possible e.g. for Jaff or other contributors to write (and maintain) a separate plug-in for his file format himself?
Yes, with the Plugin SDK
Pierre.
User avatar
Karl02
Posts: 134
Joined: Mon Sep 03, 2007 1:00 pm
Location: Germany

Post by Karl02 »

Fine! Then I would suggest that Jaff should try to write the plugin himself by using the Plugin SDK. Where is the Plugin SDK available?
-- Karl
User avatar
xnview
Author of XnView
Posts: 46255
Joined: Mon Oct 13, 2003 7:31 am
Location: France
Contact:

Post by xnview »

Karl02 wrote:Fine! Then I would suggest that Jaff should try to write the plugin himself by using the Plugin SDK. Where is the Plugin SDK available?
Here, but perhaps he is not a developer...
Pierre.
User avatar
Jaff
Posts: 67
Joined: Fri Dec 07, 2007 8:55 am
Location: Romania
Contact:

Post by Jaff »

:| I don't know how to with WinSDK. Sorry. I've made all my programs in chronologic order in BASIC, Z80ASM, QBASIC, GWBASIC, some ASM on PC, Pascal (DOS) and that's all. Has been passed too much time since I've wrote last line of a program. If anyone has time and will to make it... else we'll wait. At least the read part would be great.
Imi este indiferent ce cred ceilalti despre mine, caci oricum fiecare crede ce-i convine lui si nu ceea ce e real, doar ca mi-ar fi placut sa ma vada asa cum sint de fapt, nu asa cum poate le-ar placea lor sa creada. Ei au ales deja...
Post Reply