// Image I/O routines // #include "opengl.h" #ifdef LC_WINDOWS #include #include //#include #include #endif #include #include #include #include #include "config.h" #include "image.h" #include "file.h" // ============================================================================= // Image functions Image::Image () { m_nWidth = 0; m_nHeight = 0; m_bAlpha = false; m_pData = NULL; } Image::~Image () { free (m_pData); } void Image::FreeData () { m_nWidth = 0; m_nHeight = 0; m_bAlpha = false; free (m_pData); m_pData = NULL; } void Image::Allocate (int width, int height, bool alpha) { FreeData (); m_nWidth = width; m_nHeight = height; m_bAlpha = alpha; if (m_bAlpha) m_pData = (unsigned char*)malloc (width * height * 4); else m_pData = (unsigned char*)malloc (width * height * 3); } void Image::ResizePow2 () { int i, shifted_x, shifted_y; shifted_x = m_nWidth; for (i = 0; ((i < 16) && (shifted_x != 0)); i++) shifted_x = shifted_x >> 1; shifted_x = (i != 0) ? 1 << (i-1) : 1; shifted_y = m_nHeight; for (i = 0; ((i < 16) && (shifted_y != 0)); i++) shifted_y = shifted_y >> 1; shifted_y = (i != 0) ? 1 << (i-1) : 1; if ((shifted_x != m_nWidth) || (shifted_y != m_nHeight)) Resize (shifted_x, shifted_y); } void Image::Resize (int width, int height) { int i, j, k, components, stx, sty; float accumx, accumy; unsigned char* bits; if (m_bAlpha) components = 4; else components = 3; bits = (unsigned char*)malloc (width * height * components); for (j = 0; j < m_nHeight; j++) { accumy = (float)height*j/(float)m_nHeight; sty = (int)floor(accumy); for (i = 0; i < m_nWidth; i++) { accumx = (float)width*i/(float)m_nWidth; stx = (int)floor(accumx); for (k = 0; k < components; k++) bits[(stx+sty*width)*components+k] = m_pData[(i+j*m_nWidth)*components+k]; } } free (m_pData); m_pData = bits; m_nWidth = width; m_nHeight = height; } void Image::FromOpenGL (int width, int height) { unsigned char *buf; buf = (unsigned char*)malloc (width*height*3); FreeData (); m_pData = (unsigned char*)malloc (width*height*3); m_nWidth = width; m_nHeight = height; m_bAlpha = false; glPixelStorei (GL_PACK_ALIGNMENT, 1); glReadPixels (0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, buf); for (int row = 0; row < height; row++) memcpy (m_pData + (row*width*3), buf + ((height-row-1)*width*3), width*3); free (buf); } bool Image::FileLoad (File& file) { unsigned char buf[8]; // Read a few bytes if (file.Read (buf, 8) != 8) return false; file.Seek (-8, SEEK_CUR); // Check for the BMP header if ((buf[0] == 'B') && (buf[1] == 'M')) { if (!LoadBMP (file)) return false; return true; } #ifdef LC_HAVE_JPEGLIB if ((buf[0] == 0xFF) && (buf[1] == 0xD8)) { if (!LoadJPG (file)) return false; return true; } #endif #ifdef LC_HAVE_PNGLIB const unsigned char png_signature[8] = { 137, 80, 78, 71, 13, 10, 26, 10 }; // Check for the PNG header if (memcmp (buf, png_signature, 8) == 0) { if (!LoadPNG (file)) return false; return true; } #endif // Check for the GIF header if ((buf[0] == 'G') && (buf[1] == 'I') && (buf[2] == 'F') && (buf[3] == '8') && ((buf[4] == '7') || (buf[4] == '9')) && (buf[5] == 'a')) { if (!LoadGIF (file)) return false; return true; } // MessageBox (NULL, "Unknown File Format", "Error", MB_ICONSTOP); return false; } bool Image::FileLoad (const char* filename) { FileDisk file; if (!file.Open (filename, "rb")) return false; return FileLoad (file); } bool Image::FileSave (File& file, LC_IMAGE_OPTS* opts) const { switch (opts->format) { #ifdef LC_HAVE_JPEGLIB case LC_IMAGE_JPG: return SaveJPG (file, opts->quality, opts->interlaced); #endif case LC_IMAGE_GIF: return SaveGIF (file, opts->transparent, opts->interlaced, opts->background); case LC_IMAGE_BMP: return SaveBMP (file, opts->truecolor == false); #ifdef LC_HAVE_PNGLIB case LC_IMAGE_PNG: return SavePNG (file, opts->transparent, opts->interlaced, opts->background); #endif default: break; } // MessageBox (NULL, "Could not save file", "Error", MB_ICONSTOP); return false; } bool Image::FileSave (const char* filename, LC_IMAGE_OPTS* opts) const { char name[LC_MAXPATH], ext[5], *p; FileDisk file; bool needext = false; strcpy (name, filename); p = name + strlen (name) - 1; while ((p > name) && (*p != '/') && (*p != '\\') && (*p != '.')) p--; if (*p != '.') needext = true; else { if (strlen (p) > 5) needext = true; else { strcpy (ext, p+1); strlwr (ext); if (strcmp (ext, "bmp") == 0) opts->format = LC_IMAGE_BMP; else if (strcmp (ext, "gif") == 0) opts->format = LC_IMAGE_GIF; #ifdef LC_HAVE_JPEGLIB else if (strcmp (ext, "jpg") == 0) opts->format = LC_IMAGE_JPG; else if (strcmp (ext, "jpeg") == 0) opts->format = LC_IMAGE_JPG; #endif #ifdef LC_HAVE_PNGLIB else if (strcmp (ext, "png") == 0) opts->format = LC_IMAGE_PNG; #endif else needext = true; } } if (needext) { // no extension, add from the options switch (opts->format) { case LC_IMAGE_BMP: strcat (name, ".bmp"); break; case LC_IMAGE_GIF: strcat (name, ".gif"); break; #ifdef LC_HAVE_JPEGLIB case LC_IMAGE_JPG: strcat (name, ".jpg"); break; #endif #ifdef LC_HAVE_PNGLIB case LC_IMAGE_PNG: strcat (name, ".png"); break; #endif default: return false; } } if (!file.Open (name, "wb")) return false; return FileSave (file, opts); } // ============================================================================= // Global functions #ifdef LC_WINDOWS #include "system.h" #define AVIIF_KEYFRAME 0x00000010L // this frame is a key frame. #define LPLPBI LPBITMAPINFOHEADER * static HANDLE MakeDib (HBITMAP hbitmap, Image& image) { HANDLE hdib ; HDC hdc ; BITMAP bitmap ; UINT wLineLen ; DWORD dwSize ; DWORD wColSize ; LPBITMAPINFOHEADER lpbi ; LPBYTE lpBits ; UINT bits = 24; int i, j; GetObject(hbitmap,sizeof(BITMAP),&bitmap) ; // DWORD align the width of the DIB // Figure out the size of the colour table // Calculate the size of the DIB wLineLen = (bitmap.bmWidth*bits+31)/32 * 4; wColSize = sizeof(RGBQUAD)*((bits <= 8) ? 1<biSize = sizeof(BITMAPINFOHEADER) ; lpbi->biWidth = bitmap.bmWidth ; lpbi->biHeight = bitmap.bmHeight ; lpbi->biPlanes = 1 ; lpbi->biBitCount = (WORD) bits ; lpbi->biCompression = BI_RGB ; lpbi->biSizeImage = dwSize - sizeof(BITMAPINFOHEADER) - wColSize ; lpbi->biXPelsPerMeter = 0 ; lpbi->biYPelsPerMeter = 0 ; lpbi->biClrUsed = (bits <= 8) ? 1<biClrImportant = 0 ; // Get the bits from the bitmap and stuff them after the LPBI lpBits = (LPBYTE)(lpbi+1)+wColSize ; hdc = CreateCompatibleDC(NULL) ; GetDIBits(hdc,hbitmap,0,bitmap.bmHeight,lpBits,(LPBITMAPINFO)lpbi, DIB_RGB_COLORS); for (i = 0; i < lpbi->biHeight; i++) { unsigned char *src = image.GetData() + i * image.Width() * 3; unsigned char *dst = lpBits + (lpbi->biHeight - i - 1) * wLineLen; for (j = 0; j < lpbi->biWidth; j++) { dst[0] = src[2]; dst[1] = src[1]; dst[2] = src[0]; src += 3; dst += 3; } } // Fix this if GetDIBits messed it up.... lpbi->biClrUsed = (bits <= 8) ? 1<biSizeImage; SetRect(&strhdr.rcFrame, 0, 0, (int) plpbi[0]->biWidth, (int) plpbi[0]->biHeight); // And create the stream. if (AVIFileCreateStream(pfile, &ps, &strhdr) == AVIERR_OK) if (AVISaveOptions(NULL, 0, 1, &ps, (LPAVICOMPRESSOPTIONS FAR *) &aopts)) // if (AVISaveOptions(AfxGetMainWnd()->m_hWnd, 0, 1, &ps, (LPAVICOMPRESSOPTIONS FAR *) &aopts)) if (AVIMakeCompressedStream(&psCompressed, ps, &opts, NULL) == AVIERR_OK) if (AVIStreamSetFormat(psCompressed, 0, plpbi[0], plpbi[0]->biSize + plpbi[0]->biClrUsed * sizeof(RGBQUAD)) == AVIERR_OK) { float fPause = (float)Sys_ProfileLoadInt("Default", "AVI Pause", 100)/100; int time = (int)(fPause * 15); ///////////// set FPS time = 1; for (int i = 0; i < count; i++) { if (AVIStreamWrite(psCompressed, i * time, 1, (LPBYTE) plpbi[i] + plpbi[i]->biSize + plpbi[i]->biClrUsed * sizeof(RGBQUAD), plpbi[i]->biSizeImage, i%5 ? 0 : AVIIF_KEYFRAME, NULL, NULL) != AVIERR_OK) break; } } } FreeFrames (plpbi, count); // Now close the file if (ps) AVIStreamClose(ps); if (psCompressed) AVIStreamClose(psCompressed); if (pfile) AVIFileClose(pfile); AVIFileExit(); } #else void SaveVideo(char* filename, Image *images, int count, float fps) { // SystemDoMessageBox("Format not supported under this platform.", LC_MB_OK|LC_MB_ERROR); } #endif