#1
  1. No Profile Picture
    Junior Member
    Devshed Newbie (0 - 499 posts)

    Join Date
    Mar 2003
    Posts
    6
    Rep Power
    0

    IJG: Jpeg to HBITMAP or JPeg use in general


    Hello. First of all, I have been making use of the excellent tutorials here for some time.. but Im new to this forum. I read the rules thread and did a search on this topic.. so I apologize if I'm missing something obvious.

    I am new to the winAPI.. I am working entirely in C.. and have been doing custom shaped windows and skinning them with bmp's for this project I am doing. But I would really like to reduce the size of the exe by using a jpeg resource instead of a bitmap.

    I've downloaded and compiled the IGJ library.. and there is code in there I could use.. but Im having difficulties getting the image data into an HBITMAP. I have searched google high and low and am having problems finding any built in library.. and most '3rd party' libraries involve 2D or 3D graphics manipulation.. licensing fee's, demo versions.. ect.

    I refuse to believe I am the first individual that has ever loaded a jpg into a windows program :p, and I feel retarded that I can't figure out how everyone is doing it.

    If someone could just point me in the right direction I would greatly appreciate it. Especially if I could stick with plain old C. We are trying to save every byte possible so we can email these programs to customers.

    Thanks in advance.
  2. #2
  3. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Sep 2001
    Location
    ISRAEL
    Posts
    35
    Rep Power
    13
    ok, you should understand some basics (and please correct me if i'm wrong):
    - to load a bitmap to a reasource is as expensive as reading it from a file, or even more. (the size of the exe)
    - if you will load the bitmap from a file at run time you decrease the size of the exe but you will have to send the bmp file together with the exe.

    if you are not familiar with the API of reading from file i can explain.
    basically, to load an image from a file use LoadImage()
    (also relevant to pure C)
    "Gravitation can NOT be responsible for people falling in Love"
    (one of the most significant characters in the history, can you guess?)

    Gmorph.
  4. #3
  5. No Profile Picture
    Junior Member
    Devshed Newbie (0 - 499 posts)

    Join Date
    Mar 2003
    Posts
    6
    Rep Power
    0
    Yeah.. I can load the image from a file just fine. I included it in the exe file for ease of distribution. The difficulty I am having is using a jpg file.
  6. #4
  7. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Sep 2001
    Location
    ISRAEL
    Posts
    35
    Rep Power
    13
    i think that if the Jpeg is valid it should work well with HBITMAP but refer to MSDN for deeper description.
    try:
    BITMAP_FILE_HEADER
    BITMAP_INFO
    ...
    "Gravitation can NOT be responsible for people falling in Love"
    (one of the most significant characters in the history, can you guess?)

    Gmorph.
  8. #5
  9. No Profile Picture
    Contributing User
    Devshed God 1st Plane (5500 - 5999 posts)

    Join Date
    Oct 2000
    Location
    Back in the real world.
    Posts
    5,966
    Rep Power
    190
    starting with W2K, jpegs are natively supported by the GDI. i.e. you should be able to load them directly via LoadBitmap(), but i never tried...

    For making my programs work with all Windozes, I always use intelīs(? - the one that comes with Borland C++ Builder) jpeg library. There you can load a jpeg from a file and draw() them to any HDC. (i.e. also to a Bitmap or DIB) i donīt have any code around as i am at home, but if you can ask a more specific question, iīll gladly try to help.

    M.
  10. #6
  11. No Profile Picture
    Contributing User
    Devshed God 1st Plane (5500 - 5999 posts)

    Join Date
    Oct 2000
    Location
    Back in the real world.
    Posts
    5,966
    Rep Power
    190

    UPDATE: I found my sources...


    I just found the sources on a backup CD. I am using IJGīs library too.

    using jpeg_read_scanlines(), you can decompress the jpeg line by line to a bitmapīs bitmap-data.

    the full process is quite complicated and many lines. And as i am using Delphi version and not C, i am not willing to translate all that right now. But i could post the relevant delphi code if you want... just tell me.
  12. #7
  13. No Profile Picture
    Junior Member
    Devshed Newbie (0 - 499 posts)

    Join Date
    Mar 2003
    Posts
    6
    Rep Power
    0
    It looks like Intel isn't offering their jpg package anymore. Its now part of thier IPP package you have to purchase.

    So IJG it is. If I'm going to work scanline to scanline, don't I need to invert the image? That is.. aren't bmp's stored from bottom to top?
  14. #8
  15. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Aug 2002
    Posts
    272
    Rep Power
    18
    I think the native support of JPEG images only works with a printer DC.
  16. #9
  17. No Profile Picture
    Contributing User
    Devshed God 1st Plane (5500 - 5999 posts)

    Join Date
    Oct 2000
    Location
    Back in the real world.
    Posts
    5,966
    Rep Power
    190
    3dfxMM: possible. as said, i never tested it since my software needs to work with older windozes too.

    grunt:
    don't I need to invert the image? That is.. aren't bmp's stored from bottom to top?
    so? how hard would it be to read the scanlines top to bottom and write bottom to top?

    But i canīt remember this strange behaviour on BMPs, could be that Delphi hides it from the user though...
  18. #10
  19. No Profile Picture
    Junior Member
    Devshed Newbie (0 - 499 posts)

    Join Date
    Mar 2003
    Posts
    6
    Rep Power
    0
    so? how hard would it be to read the scanlines top to bottom and write bottom to top?
    I wasn't commenting on difficulty.. but trying to clarify what would need to be done. I recall some of the IJG code reversing the scanlines for a bmp conversion.. and difficult or not, its somewhat important to get the pixel data correct.

    I think I can organize thier code well enough. If there aren't well known libraries or methods.. I guess my question becomes, how would one create/modify an HBITMAP with this data?
  20. #11
  21. No Profile Picture
    Contributing User
    Devshed God 1st Plane (5500 - 5999 posts)

    Join Date
    Oct 2000
    Location
    Back in the real world.
    Posts
    5,966
    Rep Power
    190
    its somewhat important to get the pixel data correct.
    of course it is :)
    how would one create/modify an HBITMAP with this data?
    Just as you would do with any other bitmap too...
    Code:
    pseudocode:
    ptr=CreateBitmap(width, height)
    bmpsize=width*height*bpp // bpp=bytes per pixel
    ptr+=sizeof(BITMAP_INFO)+bmpsize;
    
    for (i=0;i<height;i++)
      jpeg_read_scanlines(jc->d, ptr-i*width*bpp, 1);
    not syntax-checked nor logic-checked. probably needs several "+/-1" somewhere. probably all wrong and will blow up your whole PC. i take no responsibility for nothing :D

    Anyone got the time for making real code of this?
  22. #12
  23. No Profile Picture
    Junior Member
    Devshed Newbie (0 - 499 posts)

    Join Date
    Mar 2003
    Posts
    6
    Rep Power
    0
    well.. I found an easier way than converting the image scanline by scanline:

    PHP Code:
    HBITMAP ReadJpegFileLPSTR pFile )
       {
       
    HANDLE hFile;
       
    HBITMAP hBmp;
       
    DWORD dwSize;
       
    DWORD dwRead;
       
    HGLOBAL hMemJpeg;
       
    LPSTREAM lpStream;
       
    OLE_HANDLE hJpegBmp;
       
    HRESULT hr;
       
    LPPICTURE lpPicture NULL;
       
    void *pMemJpeg;

       
    /* Open the file and get the size. */
       
    if((hFile CreateFile(pFileGENERIC_READFILE_SHARE_READ,
         
    NULLOPEN_EXISTING0NULL)) == INVALID_HANDLE_VALUE)
         return 
    NULL;
       if((
    dwSize GetFileSize(hFileNULL)) == 0xFFFFFFFF)
          {
          
    CloseHandle(hFile);
          return 
    NULL;
          }

       
    /* Allocate space for file, read it in, and then close the file again. */
       
    if((hMemJpeg GlobalAlloc(GMEM_MOVEABLEdwSize)) == NULL)
          {
          
    CloseHandle(hFile);
          return 
    NULL;
          }
       if((
    pMemJpeg GlobalLock(hMemJpeg)) == NULL)
          {
          
    CloseHandle(hFile);
          
    GlobalFree(hMemJpeg);
          return 
    NULL;
          }
       if(!
    ReadFile(hFilepMemJpegdwSize, &dwReadNULL))
          {
          
    CloseHandle(hFile);
          
    GlobalFree(hMemJpeg);
          return 
    NULL;
          }
       
    CloseHandle(hFile);
       
    GlobalUnlock(hMemJpeg);

       
    /* Create the stream and load the picture. */
       
    if((hr CreateStreamOnHGlobal(hMemJpegTRUE, &lpStream)) != S_OK)
          {
          
    GlobalFree(hMemJpeg);
          return 
    NULL;
          }
       if(
    OleLoadPicture(lpStreamdwSizeFALSE, &IID_IPicture, &lpPicture) != S_OK)
          {
          
    GlobalFree(hMemJpeg);
          
    lpStream->lpVtbl->Release(lpStream);
          return 
    NULL;
          }

       
    /* Get the handle to the image, and then copy it. */
       
    if((lpPicture->lpVtbl->get_Handle(lpPicture, &hJpegBmp)) != S_OK)
          {
          
    GlobalFree(hMemJpeg);
          
    lpStream->lpVtbl->Release(lpStream);
          
    lpPicture->lpVtbl->Release(lpPicture);
          return 
    NULL;
          }
       if((
    hBmp CopyImage((HANDLE *) hJpegBmpIMAGE_BITMAP00LR_COPYRETURNORG)) == NULL)
          {
          
    GlobalFree(hMemJpeg);
          
    lpStream->lpVtbl->Release(lpStream);
          
    lpPicture->lpVtbl->Release(lpPicture);
          return 
    NULL;
          }

       
    /* Free the original image and memory. */
       
    GlobalFree(hMemJpeg);
       
    lpStream->lpVtbl->Release(lpStream);
       
    lpPicture->lpVtbl->Release(lpPicture);
       return 
    hBmp;
    /* End of ReadJpegFile(). */ 


    But now Im having issues loading the image from my resources instead of an external file. Im really not very good with the winAPI. Any ideas?
  24. #13
  25. No Profile Picture
    Junior Member
    Devshed Newbie (0 - 499 posts)

    Join Date
    Mar 2003
    Posts
    11
    Rep Power
    0
    MS GDI+ will be very helpful to you.
    It works with jpg, png, gif etc.
    It is free.

    download link:

    http://www.microsoft.com/downloads/d...DisplayLang=en
  26. #14
  27. No Profile Picture
    Junior Member
    Devshed Newbie (0 - 499 posts)

    Join Date
    Apr 2003
    Posts
    1
    Rep Power
    0
    Grunt are you looking for this? I was having some trouble doing it the right way with targa so I knew if I'll make it with bmp sure I will with tga. Anyway, one thing to remember jpeg library decodes the buffer with a sequence of RGB but bitmap RGBtag is flipped to BGR and the whole data are written flipped upside down.

    int encode_bmp(char * inbuf, int width, int height, int components)
    {
    BITMAPFILEHEADER fheader;
    BITMAPINFOHEADER iheader;
    unsigned int extrabytes, bytesize;

    memset(&fheader, 0, sizeof(BITMAPFILEHEADER));
    memset(&iheader, 0, sizeof(BITMAPINFOHEADER));

    extrabytes = (4 - (width * 3) % 4 ) % 4;
    bytesize = (width * 3 + extrabytes) * height;

    iheader.biSize = sizeof(BITMAPINFOHEADER);
    iheader.biWidth = width;
    iheader.biHeight = height;
    iheader.biPlanes = 1;
    iheader.biCompression = BI_RGB;
    iheader.biBitCount = components * 8;
    iheader.biSizeImage = bytesize;

    fheader.bfType = ((WORD)('M' << 8) | 'B');
    fheader.bfSize = 0; // can be 0 for BI_RGB
    fheader.bfOffBits = (DWORD)(sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER));


    File p("c:/somedirectory/somefile.bmp");

    if(!p.open(File::write_binary))
    {
    return 0;
    }

    p.write(&fheader, sizeof(fheader));

    p.write(&iheader, sizeof(iheader));

    struct tag
    {
    unsigned char r, g, b;
    };
    tag t;

    int pitch = width * components;
    for(int j = (height * pitch - pitch); j >= 0; j-= pitch)
    {
    for(int i = j; i < j + pitch ; i+= components)
    {
    t.r = (unsigned char)inbuf[i + 2];
    t.g = (unsigned char)inbuf[i + 1];
    t.b = (unsigned char)inbuf[i ];

    p.write(&t, sizeof(tag));
    }
    }

    p.close();

    return 1;
    }

    This code works.
    Well anyway, I've got a different problem but I see right now no way to solve it. I probably missed something inside the library but I've been wandering a week and see no solution. Can anyone tell me how to initialize the destination manager by hand NOT using as a destination a file handle but only a buffer. Just a memory to memory jpeg coding. Been searching the web up and down, nowhere to find it :))) just like grunt was. One finds tons of examples doing it the easy way where the destination is always a FILE * but this is not my case. Thank you for ANY tips. Nice day/night/whatever....

IMN logo majestic logo threadwatch logo seochat tools logo