Search code examples
c++cimage-processinggimp

Convert C-Source image dump into original image


I have created with GIMP a C-Source image dump like the following:

/* GIMP RGBA C-Source image dump (example.c) */

static const struct {
  guint      width;
  guint      height;
  guint      bytes_per_pixel; /* 2:RGB16, 3:RGB, 4:RGBA */ 
  guint8     pixel_data[304 * 98 * 2 + 1];
} example= {
  304, 98, 2,
  "\206\061\206\061..... }

Is there a way to read this in GIMP again in order to get back the original image? because it doesn't seem possible. Or does it exist a tool that can do this back-conversion?

EDITED

Following some suggestion I tried to write a simple C programme to make the reverse coversion ending up with something very similar to another code found on internet but both dont work:

#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "imgs_press.h"
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>

using namespace std;

int main(int argc, char** argv) {
    int fd;
    char *name = "orignal_img.pnm";
    fd = open(name, O_WRONLY | O_CREAT, 0644);
    if (fd == -1) {
        perror("open failed");
        exit(1);
    }

    if (dup2(fd, 1) == -1) {
        perror("dup2 failed"); 
        exit(1);
    }

    // file descriptor 1, i.e. stdout, now points to the file
    // "helloworld" which is open for writing
    // You can now use printf which writes specifically to stdout

  printf("P2\n");
  printf("%d %d\n", press_high.width, press_high.height);
  for(int x=0; x<press_high.width * press_high.height * 2; x++) {
    printf("%d ", press_high.pixel_data[x]);
  }
}

As suggested by n-1-8e9-wheres-my-share-m, maybe I need to manipulate the pixels usign the correct decode, but I have no idea how to do that, does anybody have other suggestions?

The image I got is indeed distorted: enter image description here


Solution

  • Updated Answer

    If you want to decode the RGB565 and write a NetPBM format PNM file without using ImageMagick, you can do this:

    #include <stdint.h>   /* for uint8_t */
    #include <stdio.h>    /* for printf */
    
    /* tell compiler what those GIMP types are */
    typedef int guint;
    typedef uint8_t guint8;
    
    #include <YOURGIMPIMAGE>
    
    int main(){
    
       int w = gimp_image.width;
       int h = gimp_image.height;
       int i;
       uint16_t*  RGB565p = (uint16_t*)&(gimp_image.pixel_data);
    
       /* Print P3 PNM header on stdout */
       printf("P3\n%d %d\n255\n",w, h);
    
       /* Print RGB pixels, ASCII, one RGB pixel per line */
       for(i=0;i<w*h;i++){
          uint16_t RGB565 = *RGB565p++;
          uint8_t r = (RGB565 & 0xf800) >> 8;
          uint8_t g = (RGB565 & 0x07e0) >> 3;
          uint8_t b = (RGB565 & 0x001f) << 3;
          printf("%d %d %d\n", r, g ,b);
       }
    }
    

    Compile with:

    clang example.c
    

    And run with:

    ./a.out > result.pnm
    

    I have not tested it too extensively beyond your sample image, so you may want to make a test image with some reds, greens, blues and shades of grey to ensure that all my bit-twiddling is correct.

    Original Answer

    The easiest way to get your image back would be... to let ImageMagick do it.

    So, take your C file and add a main() to it that simply writes the 304x98x2 bytes starting at &(example.pixel_data) to stdout:

    Compile it with something like:

    clang example.c -o program    # or with GCC
    gcc example.c -o program
    

    Then run it, writing to a file for ImageMagick with:

    ./program > image.bin
    

    And tell ImageMagick its size, type and where it is and what you want as a result:

    magick -size 304x98 RGB565:image.bin result.png
    

    I did a quick, not-too-thorough test of the following code and it worked fine for an image I generated with GIMP. Note it doesn't handle alpha/transparency but that could be added if necessary. Save it as program.c:

    #include <unistd.h>   /* for write() */
    #include <stdint.h>   /* for uint8_t */
    
    /* tell compiler what those GIMP types are */
    typedef int guint;
    typedef uint8_t guint8;
    
    <PASTE YOUR GIMP FILE HERE>
    
    int main(){
    
       /* Work out how many bytes to write */
       int nbytes = example.width * example.height * 2;
    
       /* Write on stdout for redirection to a file - may need to reopen in binary mode if on Windows */
       write(1, &(example.pixel_data), nbytes);
    }
    

    If I run this with the file you provided via Google Drive I get:

    enter image description here