Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1] 2  Все   Вниз
  Печать  
Автор Тема: Преобразование HDC в BITMAP  (Прочитано 22105 раз)
0 Пользователей и 1 Гость смотрят эту тему.
zeo
Интересующийся

ru
Offline Offline
Пол: Мужской
Челябинск, Россия


« : 30-09-2008 09:33 » 

Есть HDC, на ней очнеб много разных объектов, текст, графика и т.д.
Как сохранить эту HDC в BITMAP, чтобы можно было редактировать эту структуру.

Вообще цель такая: создавать водяные знаки перед посылкой на принтер.
Записан
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


WWW
« Ответ #1 : 30-09-2008 09:50 » 

печатью не занимался, но мне кажется, достаточно будет, когда шлёшь на принтер, на контексте принтера просто сверху шлёпнуть знаки и всё Улыбаюсь


пользоваться
CDC::BOOL BitBlt(...)

CDC::GetPixel()
CDC::SetPixel()


---------
тьфу, блин, вся я со своим MFC Улыбаюсь))

но в api есть аналогичные функции для контекста
Записан

zeo
Интересующийся

ru
Offline Offline
Пол: Мужской
Челябинск, Россия


« Ответ #2 : 30-09-2008 09:53 » 

достаточно будет, когда шлёшь на принтер, на контексте принтера просто сверху шлёпнуть знаки и всё Улыбаюсь
Если шлепнешь, то закроешь то, что находится под печатью.

SetPixel работает только если на HDC выделяемая облать известна (ее тип) но так как на Контекст можеет пойти много разных элементов, то не получается определить цвет. Для этого как раз и надо HDC преобразовать в BITMAP, чтобы цвет определить.
Записан
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


WWW
« Ответ #3 : 30-09-2008 09:57 » 

всегда думал, что GetPixel спасёт в данном случае Улыбаюсь

а в Bitblt - там куча опций по накладыванию битмапа.

Кстати, SetPixelV работает чуточку быстрее, чем SetPixel
« Последнее редактирование: 30-09-2008 09:59 от Алексей1153++ » Записан

zeo
Интересующийся

ru
Offline Offline
Пол: Мужской
Челябинск, Россия


« Ответ #4 : 30-09-2008 09:58 » 

всегда думал, что GetPixel спасёт в данном случае
Пробовал - говорит ошибку. А SetPixel работает нормально.
Записан
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


WWW
« Ответ #5 : 30-09-2008 09:59 » 

я предыдущий пост правил, глянь

А что за ошибка - что пишет ?
Записан

zeo
Интересующийся

ru
Offline Offline
Пол: Мужской
Челябинск, Россия


« Ответ #6 : 30-09-2008 10:02 » 

Возвращает -1.
А GetLastError() возвращает 0.

Но в MSDN пишут:If the pixel is outside of the current clipping region, the return value is CLR_INVALID. Это как раз -1.

Но я не могу выделить этот clipping region, потому что не знаю какие объекты на контексте.
Записан
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


WWW
« Ответ #7 : 30-09-2008 10:05 » 

хм...
Цитата
Not all devices support GetPixel. An application should call GetDeviceCaps to determine whether a specified device supports this function.

тогда пробовай

GetStockObject()
GetCurrentBitmap()
« Последнее редактирование: 30-09-2008 10:07 от Алексей1153++ » Записан

Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


WWW
« Ответ #8 : 30-09-2008 10:08 » 

в MFC развёрнуто так
Код:
_AFXWIN_INLINE CBitmap* CDC::GetCurrentBitmap() const
{
 ASSERT(m_hAttribDC != NULL);
 return CBitmap::FromHandle((HBITMAP)::GetCurrentObject(m_hAttribDC, OBJ_BITMAP));
}
Записан

zeo
Интересующийся

ru
Offline Offline
Пол: Мужской
Челябинск, Россия


« Ответ #9 : 30-09-2008 10:11 » 

GetCurrentBitmap()
Returns a pointer to the currently selected CBitmap object.

Вернет только Bitmap, но на контексте может быть и тескст, и могут Pen'ом нарисовать и т.п.
Записан
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


WWW
« Ответ #10 : 30-09-2008 10:14 » 

всё, что нарисовано, будет на битмапе. Или у тебя какой то особенный контекст, с поддержкой объектов ?
Записан

Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


WWW
« Ответ #11 : 30-09-2008 10:16 » 

и вапще Улыбаюсь GetPixel () точно везде -1 вернул ? А если сканировать контекст и накладывать пикселы знака только там, где не -1 вернулось ?
Записан

zeo
Интересующийся

ru
Offline Offline
Пол: Мужской
Челябинск, Россия


« Ответ #12 : 30-09-2008 10:25 » 

Сейчас попробовал еще раз.
Код:
HBITMAP hbit = (HBITMAP)GetCurrentObject(hdc, OBJ_BITMAP);
BITMAP bmp;
GetObject(hbit, sizeof(BITMAP), (LPVOID) &bmp);
Получилось: bmp.bmBitsPixels = 1

и вапще Улыбаюсь GetPixel () точно везде -1 вернул ? А если сканировать контекст и накладывать пикселы знака только там, где не -1 вернулось ?
-1 на всем контексте. (конекст обычный)
Записан
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


WWW
« Ответ #13 : 30-09-2008 10:39 » 

Specifies the number of bits required to indicate the color of a pixel.

чёрно белый принтер ?
Записан

zeo
Интересующийся

ru
Offline Offline
Пол: Мужской
Челябинск, Россия


« Ответ #14 : 30-09-2008 10:58 » 

чёрно белый принтер ?
Нет.
Записан
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


WWW
« Ответ #15 : 30-09-2008 11:04 » 

тогда я не знаю. Ждём опытных
Записан

RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #16 : 30-09-2008 13:46 » 

zeo, попробуй так: создать битмап нужного размера, потом SelectObject() битмап к HDC, потом рисовать в HDC.
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


WWW
« Ответ #17 : 01-10-2008 04:00 » 

наверное так и надо как раз. Только потом не забыть вернуть старый битмап в контекст
Записан

zeo
Интересующийся

ru
Offline Offline
Пол: Мужской
Челябинск, Россия


« Ответ #18 : 01-10-2008 06:31 » 

Попробовал - получился черный рисунок почти как Малевича.
Как пишут в MSDN:
The SelectObject function selects an object into the specified device context (DC). The new object replaces the previous object of the same type.

Соответсвенно происходит замена моего Битмэпа, потому что при рисовании применяются разные другие объекты.
Записан
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


WWW
« Ответ #19 : 01-10-2008 06:37 » 

всё правильно! Ты же при этом старый и извлекаешь - функция его возвращает. На новом надо рисовать, выводить на печать, а потом не забыть вернуть старый взад
Записан

Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


WWW
« Ответ #20 : 01-10-2008 06:38 » 

zeo, вечером мне просигналь, а лучше проект скинь, попробую на практике полапать всё. А то гадать долго можно
Записан

zeo
Интересующийся

ru
Offline Offline
Пол: Мужской
Челябинск, Россия


« Ответ #21 : 01-10-2008 06:46 » 

Что-то ступр на меня нашел.
То есть алгоритм такой:
1. Создаем на HDC битмап по размеру контекста.
2. SelectObject для этого битмапа.
3. Если в программе вызывается например SelectObject(hdc, font), то сохранить объект, на который он ссылается (наш битмэп), и после этого вызвать SelectObject(hdc, bitmap).
Записан
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #22 : 01-10-2008 07:22 » 

zeo, только не создавай Compatible Bitmap - создавай того же размера, но полноценный RGB.
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


WWW
« Ответ #23 : 01-10-2008 07:35 » 

при чём тут font ?

oldBMP=SelectObject(hdc, newBMP);
...
...
SelectObject(hdc, oldBMP);
Записан

zeo
Интересующийся

ru
Offline Offline
Пол: Мужской
Челябинск, Россия


« Ответ #24 : 01-10-2008 08:51 » 

Сразу после вызова StartPage:
Код:
POINT pt;
pt.x = GetDeviceCaps(hdc, HORZRES); 
pt.y = GetDeviceCaps(hdc, VERTRES); 

hb = (HBITMAP)CreateBitmap(pt.x, pt.y, 1, 24,NULL );
SelectObject ( hdc, hb );

Перед тем как вызвать EndPage:
Код:
CreateBMPFile(L"e:\\1.bmp", CreateBitmapInfoStruct(hb), hb, hdc);
(Эта функция сохраняет бит-мэп в файл).

Получается bmp файл 24-разрядный, но с черным цветом.
« Последнее редактирование: 01-10-2008 08:55 от zeo » Записан
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


WWW
« Ответ #25 : 01-10-2008 09:03 » 

1) а где само рисование то?
2) если этого ничего не делать, то на бумагу то выходит что нибудь ?
Записан

zeo
Интересующийся

ru
Offline Offline
Пол: Мужской
Челябинск, Россия


« Ответ #26 : 01-10-2008 09:11 » 

Само рисование находится между StartPage и EndPage, но там выводит другая часть программы, которая со мной не связана. Я пишу обертку для этих функций, чтобы водяные знаки выводились.

Да на принтер все идет нормально.

Код:
hbit = (HBITMAP) LoadImage(0,
PathToBitmap,
IMAGE_BITMAP,
0, 0, LR_CREATEDIBSECTION | LR_LOADFROMFILE);

GetObject(hbit, sizeof(BITMAP), (LPVOID) &bm);
sizeinfo = sizeof(BITMAPINFO);
info = (LPBITMAPINFO) malloc(sizeinfo);
info->bmiHeader.biSize          = sizeof(BITMAPINFOHEADER);
info->bmiHeader.biWidth         = bm.bmWidth;
info->bmiHeader.biHeight        = bm.bmHeight;
info->bmiHeader.biPlanes        = 1;
info->bmiHeader.biBitCount      = bm.bmBitsPixel * bm.bmPlanes;
info->bmiHeader.biCompression   = BI_RGB;
info->bmiHeader.biSizeImage     = bm.bmWidthBytes * bm.bmHeight;
info->bmiHeader.biXPelsPerMeter = 0;
info->bmiHeader.biYPelsPerMeter = 0;
info->bmiHeader.biClrUsed       = 0;
info->bmiHeader.biClrImportant  = 0;
{
HBITMAP hOldBitmap;
HDC     hMemDC     = CreateCompatibleDC(NULL);
hOldBitmap = (HBITMAP) SelectObject(hMemDC, hbit);
GetDIBColorTable(hMemDC, 0, 0, rgb);
info->bmiColors[0] = rgb[0];
SelectObject(hMemDC, hOldBitmap);
DeleteDC(hMemDC);
}
StretchDIBits(hdc, 0, 0, bm.bmWidth, bm.bmHeight, 0, 0, bm.bmWidth, bm.bmHeight,
bm.bmBits, info, DIB_RGB_COLORS, SRCCOPY);

Я вывожу на принтер рисунок из файла, путь к которому указан в PathToBitmap. Но если его перед выводить, то его затирают объекты, которые вызываются во время рисования. А если выводить после - то он сам закрывает собой вывод.
Записан
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


WWW
« Ответ #27 : 01-10-2008 09:43 » 

вот этот момент чем то смущает

Код:
{
HBITMAP hOldBitmap;
HDC     hMemDC     = CreateCompatibleDC(NULL);
hOldBitmap = (HBITMAP) SelectObject(hMemDC, hbit);
GetDIBColorTable(hMemDC, 0, 0, rgb);
info->bmiColors[0] = rgb[0];
SelectObject(hMemDC, hOldBitmap);
DeleteDC(hMemDC);
}
StretchDIBits(hdc, 0, 0, bm.bmWidth, bm.bmHeight, 0, 0, bm.bmWidth, bm.bmHeight,
bm.bmBits, info, DIB_RGB_COLORS, SRCCOPY);


зачем создавать контекст, он ведь уже есть - из StartPage ?
почему всё это удаляется ДО вызова EndPage?

а вообще, в мсдн такой пример есть, посмотри, может это как раз что надо

Код:
    // Zero and then initialize the members of a DOCINFO structure.
 
    memset( &di, 0, sizeof(DOCINFO) );
    di.cbSize = sizeof(DOCINFO);
    di.lpszDocName = "Bitmap Printing Test";
    di.lpszOutput = (LPTSTR) NULL;
    di.lpszDataType = (LPTSTR) NULL;
    di.fwType = 0;
 
    // Begin a print job by calling the StartDoc function.
 
    nError = StartDoc(pd.hDC, &di);
    if (nError == SP_ERROR)
    {
        errhandler("StartDoc", hwnd);
        goto Error;
    }
 
    // Inform the driver that the application is about to begin
    // sending data.
 
    nError = StartPage(pd.hDC);
    if (nError <= 0)
    {
        errhandler("StartPage", hwnd);
        goto Error;
    }
 
    // Retrieve the number of pixels-per-logical-inch in the
    // horizontal and vertical directions for the display upon which
    // the bitmap was created. These are likely the same as for
    // the present display, so we use those values here.
 
    hWinDC = GetDC(hWnd);
    fLogPelsX1 = (float) GetDeviceCaps(hWinDC, LOGPIXELSX);
    fLogPelsY1 = (float) GetDeviceCaps(hWindDC, LOGPIXELSY);
 
    // Retrieve the number of pixels-per-logical-inch in the
    // horizontal and vertical directions for the printer upon which
    // the bitmap will be printed.
 
    fLogPelsX2 = (float) GetDeviceCaps(pd.hDC, LOGPIXELSX);
    fLogPelsY2 = (float) GetDeviceCaps(pd.hDC, LOGPIXELSY);
 
    // Determine the scaling factors required to print the bitmap and
    // retain its original proportions.
 
    if (fLogPelsX1 > fLogPelsX2)
        fScaleX = (fLogPelsX1 / fLogPelsX2);
    else fScaleX = (fLogPelsX2 / fLogPelsX1);
 
    if (fLogPelsY1 > fLogPelsY2)
        fScaleY = (fLogPelsY1 / fLogPelsY2);
    else fScaleY = (fLogPelsY2 / fLogPelsY1);
 
    // Compute the coordinates of the upper left corner of the
    // centered bitmap.
 
    cWidthPels = GetDeviceCaps(pd.hDC, HORZRES);
    xLeft = ((cWidthPels / 2) - ((int) (((float) bmih.biWidth)
            * fScaleX)) / 2);
    cHeightPels = GetDeviceCaps(pd.hDC, VERTRES);
    yTop = ((cHeightPels / 2) - ((int) (((float) bmih.biHeight)
            * fScaleY)) / 2);
 
    // Use StretchDIBits to scale the bitmap and maintain
    // its original proportions (that is, if the bitmap was square
    // when it appeared in the application's client area, it should
    // also appear square on the page).
 
    if (StretchDIBits(pd.hDC, xLeft, yTop, (int) ((float) bmih.biWidth
        * fScaleX), (int) ((float) bmih.biHeight * fScaleY), 0, 0,
        bmih.biWidth, bmih.biHeight, lpBits, lpBitsInfo, iUsage,
        SRCCOPY) == GDI_ERROR)
    {
        errhandler("StretchDIBits Failed", hwnd);
    }
 
 
    // Retrieve the width of the string that specifies the full path
    // and filename for the file that contains the bitmap.
 
    GetTextExtentPoint32(pd.hDC, ofn.lpstrFile,
        ofn.nFileExtension + 3, &szMetric);
 
    // Compute the starting point for the text-output operation. The
    // string will be centered horizontally and positioned three lines
    // down from the top of the page.
 
    xLeft = ((cWidthPels / 2) - (szMetric.cx / 2));
    yTop = (szMetric.cy * 3);
 
    // Print the path and filename for the bitmap, centered at the top
    // of the page.
 
    TextOut(pd.hDC, xLeft, yTop, ofn.lpstrFile,
        ofn.nFileExtension + 3);
 
    // Determine whether the user has pressed the Cancel button in the
    // AbortPrintJob dialog box; if the button has been pressed, call
    // the AbortDoc function. Otherwise, inform the spooler that the
    // page is complete.
 
    nError = EndPage(pd.hDC);
 
    if (nError <= 0)
    {
        errhandler("EndPage", hwnd);
        goto Error;
    }
 
    // Inform the driver that document has ended.
 
    nError = EndDoc(pd.hDC);
    if (nError <= 0)
        errhandler("EndDoc", hwnd);
 
Error:
    // Enable the application's window.
 
    EnableWindow(hwnd, TRUE);
 
    // Remove the AbortPrintJob dialog box.
 
    DestroyWindow(hdlgCancel);
 
    // Delete the printer DC.
 
    DeleteDC(pd.hDC);

а если изображения "закрывают", как ты говоришь, то всё ок - тебе лишь надо знаки прозрачно наложить на рисунок )
Записан

zeo
Интересующийся

ru
Offline Offline
Пол: Мужской
Челябинск, Россия


« Ответ #28 : 01-10-2008 09:50 » 

Этот код:
Код:
{
HBITMAP hOldBitmap;
HDC     hMemDC     = CreateCompatibleDC(NULL);
hOldBitmap = (HBITMAP) SelectObject(hMemDC, hbit);
GetDIBColorTable(hMemDC, 0, 0, rgb);
info->bmiColors[0] = rgb[0];
SelectObject(hMemDC, hOldBitmap);
DeleteDC(hMemDC);
}
Только с одной целью: определить info->bmiColors[0].

Прозрачно не получается накладывать рисунок.
Записан
zeo
Интересующийся

ru
Offline Offline
Пол: Мужской
Челябинск, Россия


« Ответ #29 : 01-10-2008 09:51 » 

Аналогичная проблема на rsdn'е была поднята: http://www.rsdn.ru/Forum/?mid=1819942. Но без решения.
Записан
Страниц: [1] 2  Все   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines