/*------------------------------------------------------------------* * * * Video Toolkit For OS/2 Version 1.0 * * Example PM Application No. 5. * * Date : 13/07/95. * * Copyright Abbotsbury Software Ltd. (c), United Kingdom. 1999. * * * * Filename : ex5cap.c * * * *------------------------------------------------------------------*/ #define INCL_PM #define INCL_DOS #define INCL_SW #define INCL_OS2MM #include #include #include #include #include #include #include #include #include #include #include "ex5.h" #include "ex5cap.h" #include "rgbconv.h" extern HAB Hab; extern HWND HwndFrame, HwndClient; extern LONG Width, Height, X, Y; extern BOOL CaptureOpen, ConvertASM; extern LONG NumColours; extern LONG Colours[256]; extern void msg_box (UCHAR *txt, UCHAR *title, ULONG options); extern void err_msg (CHAR *text); static UCHAR *Bmp_data; static BITMAPINFOHEADER2 Bmp_ihdr; static CHAR txt[80]; // function protocols. MRESULT EXPENTRY CaptureDlgProc (HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2); // static function protocols. static BOOL create_bitmap_Hdc_Hps (PHDC phdc, PHPS phps); static void bmp_file_proc (void); static LONG hextol (char *t); static void convert_YUV422_RGB (BYTE *src, BYTE *dest, ULONG num); static BYTE get_colour (HPS hps, USHORT r, USHORT g, USHORT b); // functions. MRESULT EXPENTRY CaptureDlgProc (HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2) { static HWND hwnd_menu; static HBITMAP hbm; static HPS hpsBMP; static HDC hdcBMP; static LONG x, y, width, height; static UCHAR *buf, *data; BITMAPINFO2 bmpi; PBITMAPINFO2 pbmpi = &bmpi; PBITMAPINFOHEADER2 pbmpih = &Bmp_ihdr; ULONG len, i, j, size; ERRORID err; LONG bx, by, ty; HPS hps; RECTL rcl; POINTL pts; APIRET rc; SWP swp; switch (msg) { case WM_INITDLG : hwnd_menu = WinLoadMenu (hwnd, NULLHANDLE, IDD_CAPTURE); x = y = 0; bx = WinQuerySysValue (HWND_DESKTOP, SV_CXDLGFRAME); by = WinQuerySysValue (HWND_DESKTOP, SV_CYDLGFRAME); ty = WinQuerySysValue (HWND_DESKTOP, SV_CYTITLEBAR); WinSetWindowPos (hwnd, HWND_TOP, x, y, Width + (bx * 2), Height + (by * 2) + ty, SWP_SIZE | SWP_MOVE); WinSendMsg (hwnd, MSG_CAPTURE, NULL, NULL); CaptureOpen = TRUE; break; case WM_PAINT : hps = WinBeginPaint (hwnd, NULLHANDLE, &rcl); WinQueryWindowRect (hwnd, &rcl); WinFillRect (hps, &rcl, CLR_PALEGRAY); bx = WinQuerySysValue (HWND_DESKTOP, SV_CXDLGFRAME); by = WinQuerySysValue (HWND_DESKTOP, SV_CYDLGFRAME); pts.x = 0 + bx; pts.y = 0 + by; WinDrawBitmap (hps, hbm, NULL, &pts, CLR_NEUTRAL, CLR_BACKGROUND, DBM_NORMAL | DBM_IMAGEATTRS); WinDrawBorder (hps, &rcl, bx, by, CLR_YELLOW, CLR_DARKGRAY, DB_AREAATTRS | DB_DLGBORDER); WinEndPaint (hps); break; case WM_COMMAND : switch (SHORT1FROMMP (mp1)) { case IDM_CAPT_FILE_SAVE : bmp_file_proc (); return 0; default : break; } return 0; case WM_CLOSE : case WM_QUIT : case WM_DESTROY : GpiDestroyPS (hpsBMP); DevCloseDC (hdcBMP); GpiDeleteBitmap (hbm); DosFreeMem (Bmp_data); DosFreeMem (buf); CaptureOpen = FALSE; break; case MSG_CAPTURE : if (hbm) { GpiDestroyPS (hpsBMP); DevCloseDC (hdcBMP); GpiDeleteBitmap (hbm); } width = (Width / 8) * 8; height = (Height / 8) * 8; WinQueryWindowPos (hwnd, &swp); x = swp.x; y = swp.y; bx = WinQuerySysValue (HWND_DESKTOP, SV_CXDLGFRAME); by = WinQuerySysValue (HWND_DESKTOP, SV_CYDLGFRAME); ty = WinQuerySysValue (HWND_DESKTOP, SV_CYTITLEBAR); WinSetWindowPos (hwnd, HWND_TOP, x, swp.y, Width + (bx * 2), Height + (by * 2) + (ty * 2), SWP_SIZE | SWP_MOVE); len = (ULONG)((width * height) * 2); rc = DosAllocMem ((PPVOID)&buf, len + 4L, (PAG_COMMIT | PAG_WRITE)); if (rc) { sprintf (txt, "error - DosAllocMem %d", rc); msg_box (txt, "Error", MB_ERROR | MB_OK); return; } rc = DosAllocMem ((PPVOID)&Bmp_data, (width * height * 4) + 4L, (PAG_WRITE | PAG_COMMIT)); if (rc) { sprintf (txt, "error - DosAllocMem %d", rc); msg_box (txt, "Error", MB_ERROR | MB_OK); return; } if (!ConvertASM) { rc = DosAllocMem ((PPVOID)&data, (width * height * 4) + 4L, (PAG_WRITE | PAG_COMMIT)); if (rc) { sprintf (txt, "error - DosAllocMem %d", rc); msg_box (txt, "Error", MB_ERROR | MB_OK); return; } } VcaiImageScaleGet ((USHORT)len, (ULONG)buf, (USHORT)x, (USHORT)(y + height), (USHORT)width, (USHORT)height, (USHORT)X, (USHORT)Y, (USHORT)width, (USHORT)height); if (ConvertASM) { YUV422_TO_IRGB24 ((USHORT *)buf, (BYTE *)Bmp_data, (ULONG)width, (ULONG)height); } else { convert_YUV422_RGB (buf, data, len); // Transfer scan lines to bottom up. for (i = 0, j = (width * height) - width; i < height; i++, j-=width) { memcpy (Bmp_data + j, data + (i*width), (size_t)width); } } if (ConvertASM) { pbmpi = malloc (sizeof (BITMAPINFO2)); } else { size = (sizeof (RGB2)) * (NumColours - 1); pbmpi = malloc (sizeof (BITMAPINFO2) + size); } pbmpih->cbFix = pbmpi->cbFix = sizeof (BITMAPINFOHEADER2); pbmpih->cx = pbmpi->cx = width; pbmpih->cy = pbmpi->cy = height; pbmpih->cPlanes = pbmpi->cPlanes = 1; if (!ConvertASM) { switch ((ULONG)NumColours) { case 2 : pbmpih->cBitCount = pbmpi->cBitCount = 1; break; case 16 : pbmpih->cBitCount = pbmpi->cBitCount = 4; break; case 256 : pbmpih->cBitCount = pbmpi->cBitCount = 8; break; default: break; } } else { pbmpih->cBitCount = pbmpi->cBitCount = 24; } pbmpih->ulCompression = pbmpi->ulCompression = BCA_UNCOMP; pbmpih->cbImage = pbmpi->cbImage = 0L; pbmpih->cxResolution = pbmpi->cxResolution = width; pbmpih->cyResolution = pbmpi->cyResolution = height; if (!ConvertASM) { pbmpih->cclrUsed = pbmpi->cclrUsed = NumColours; pbmpih->cclrImportant = pbmpi->cclrImportant = NumColours; } else { pbmpih->cclrUsed = pbmpi->cclrUsed = 0L; pbmpih->cclrImportant = pbmpi->cclrImportant = 0L; } pbmpih->usUnits = pbmpi->usUnits = BRU_METRIC; pbmpih->usReserved = pbmpi->usReserved = 0; pbmpih->usRecording = pbmpi->usRecording = BRA_BOTTOMUP; pbmpih->usRendering = pbmpi->usRendering = BRH_NOTHALFTONED; pbmpih->cSize1 = pbmpi->cSize1 = 0L; pbmpih->cSize2 = pbmpi->cSize2 = 0L; pbmpih->ulColorEncoding = pbmpi->ulColorEncoding = BCE_RGB; if (!ConvertASM) { for (i = 0; i < NumColours; i++) { pbmpi->argbColor[i].bBlue = (BYTE)(Colours[i] & 0x000000FF); pbmpi->argbColor[i].bGreen = (BYTE)((Colours[i] & 0x0000FF00) / 0x100); pbmpi->argbColor[i].bRed = (BYTE)((Colours[i] & 0x00FF0000) / 0x10000); pbmpi->argbColor[i].fcOptions = 0; } } create_bitmap_Hdc_Hps (&hdcBMP, &hpsBMP); hbm = GpiCreateBitmap (hpsBMP, pbmpih, 0L, NULL, NULL); if (hbm == 0) { err_msg ("GpiCreateBitmap"); return; } if (GpiSetBitmap (hpsBMP, hbm) == HBM_ERROR) { err_msg ("GpiSetBitmap"); return; } if (GpiSetBitmapBits (hpsBMP, 0L, height, Bmp_data, pbmpi) != height) { err_msg ("GpiSetBitmapBits"); return; } DosFreeMem (data); DosFreeMem (buf); DosFreeMem (Bmp_data); free (pbmpi); WinQueryWindowRect (hwnd, &rcl); WinInvalidateRect (hwnd, &rcl, TRUE); break; default : break; } return WinDefDlgProc (hwnd, msg, mp1, mp2); } static BOOL create_bitmap_Hdc_Hps (PHDC phdc, PHPS phps) { SIZEL sizl; HDC hdc; HPS hps; DEVOPENSTRUC dop = {NULL, "DISPLAY", NULL, NULL, NULL, NULL, NULL, NULL, NULL}; hdc = DevOpenDC (Hab, OD_MEMORY, "*", 3L, (PDEVOPENDATA) &dop, NULLHANDLE); if (!hdc) return (FALSE); sizl.cx = sizl.cy = 1L; hps = GpiCreatePS (Hab, hdc, &sizl, PU_PELS | GPIA_ASSOC | GPIT_MICRO); if (!hps) return (FALSE); *phdc = hdc; *phps = hps; return (TRUE); } static void bmp_file_proc () { HWND hwndDlg; CHAR title[20]; FILE *fd; BYTE *d; LONG width, height; ULONG i; FILEDLG file_dlg; BITMAPFILEHEADER2 bmp_fhdr; // initialise FILEDLG structure. memset (&file_dlg, 0, sizeof (FILEDLG)); file_dlg.cbSize = sizeof (FILEDLG); file_dlg.fl = FDS_HELPBUTTON | FDS_CENTER | FDS_SAVEAS_DIALOG; sprintf (title, "Save bitmap"); file_dlg.pszTitle = title; sprintf (file_dlg.szFullFile, "*.bmp"); // open file dialog. hwndDlg = WinFileDlg (HWND_DESKTOP, HwndFrame, &file_dlg); if (hwndDlg && (file_dlg.lReturn != DID_OK)) return; // save bitmap. fd = fopen (file_dlg.szFullFile, "wb"); if (!fd) return; bmp_fhdr.usType = BFT_BMAP; bmp_fhdr.cbSize = sizeof (BITMAPFILEHEADER2); bmp_fhdr.offBits = bmp_fhdr.cbSize; bmp_fhdr.bmp2 = Bmp_ihdr; d = (BYTE *)&bmp_fhdr; for (i = 0; i < (sizeof (BITMAPFILEHEADER2)); i++, d++) fputc ((INT) *d, fd); width = (Width / 8) * 8; height = (Height / 8) * 8; for (i = 0; i < (width * height * 4); i++) fputc (Bmp_data[i], fd); fclose (fd); } static LONG hextol (char *t) { LONG tot; tot = 0L; while (*t) { if (*t >= '0' && *t <= '9') break; if (*t >= 'a' && *t <= 'f') break; if (*t >= 'A' && *t <= 'F') break; t++; } while (*t) { if ((!(*t >= '0' && *t <= '9')) && (!(*t >= 'a' && *t <= 'f')) && (!(*t >= 'A' && *t <= 'F'))) break; if (*t >= '0' && *t <= '9') { tot *= 16L; tot += (*t - '0'); t++; continue; } if (*t >= 'a' && *t <= 'f') { tot *= 16L; tot += (*t - 'a') + 0xA; t++; continue; } if (*t >= '0' && *t <= '9') { tot *= 16L; tot += (*t - 'A') + 0xA; t++; continue; } } return tot; } static void convert_YUV422_RGB (BYTE *src, BYTE *dest, ULONG len) { /* Convert YUV 4:2:2 image data to RGB format for use in creating a bitmap of the image. This code only supports resolutions with 256 colours. Rt = (V * 179) / 127. Bt = (U * 227) / 127. R1 = Rt + Y1. R2 = Rt + Y2. B1 = Bt + Y1. B2 = Bt + Y2. G1 = ((170 * Y1) - (51 * R1) - (19 * B1)) / 100. G2 = ((170 * Y2) - (51 * R2) - (19 * B2)) / 100. */ USHORT R1, R2, G1, G2, B1, B2, Y1, Y2, Rt, Bt; SHORT U, V; LONG RGB1, RGB2, d; ULONG i, j; HPS hps; hps = WinGetPS (HwndClient); if (!GpiCreateLogColorTable (hps, LCOL_RESET, LCOLF_CONSECRGB, 0L, NumColours, Colours)) err_msg ("GpiCreateLogColorTable"); for (i = 0, j = 0; i < len; i+=4, j+=2) { Y1 = (USHORT)(src[i] & 0xff); U = (SHORT)(src[i+1] & 0xff); Y2 = (USHORT)(src[i+2] & 0xff); V = (SHORT)(src[i+3] & 0xff); U -= 128; V -= 128; Rt = (V * 179) / 127; Bt = (U * 227) / 127; R1 = Rt + Y1; R2 = Rt + Y2; B1 = Bt + Y1; B2 = Bt + Y2; G1 = ((170 * Y1) - (51 * R1) - (19 * B1)) / 100; G2 = ((170 * Y2) - (51 * R2) - (19 * B2)) / 100; R1 = (R1 >= 0x100) ? 0xFF : (R1 <= 0) ? 0 : R1; R2 = (R2 >= 0x100) ? 0xFF : (R2 <= 0) ? 0 : R2; B1 = (B1 >= 0x100) ? 0xFF : (B1 <= 0) ? 0 : B1; B2 = (B2 >= 0x100) ? 0xFF : (B2 <= 0) ? 0 : B2; G1 = (G1 >= 0x100) ? 0xFF : (G1 <= 0) ? 0 : G1; G2 = (G2 >= 0x100) ? 0xFF : (G2 <= 0) ? 0 : G2; dest[j] = get_colour (hps, R1, G1, B1); dest[j+1] = get_colour (hps, R2, G2, B2); } WinReleasePS (hps); } static BYTE get_colour (HPS hps, USHORT r, USHORT g, USHORT b) { ULONG i; LONG d; LONG rgb; rgb = (LONG)((r * 0x10000) + (g * 0x100) + b); rgb = GpiQueryNearestColor (hps, 0, rgb); d = GpiQueryColorIndex (hps, 0, rgb); return (BYTE)(d & 0xff); }