powered by simpleCommunicator - 2.0.59     © 2025 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Visual Basic [игнор отключен] [закрыт для гостей] / Как записать растр в файл? Как прочесть растр из файла?
9 сообщений из 9, страница 1 из 1
Как записать растр в файл? Как прочесть растр из файла?
    #36635493
litvin44
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Создаю "виртуальное" окно и растр в нем API-функциями
hBM = CreateCompatibleBitmap(hGetDC, W, H)
hDC = CreateCompatibleDC(0)
Q = SelectObject(hDC, hBM)

Потом рисую в этом окне. Как сохранить рисунок в файл?

И, наоборот, как прочесть в такое окно растр из файла?
...
Рейтинг: 0 / 0
Как записать растр в файл? Как прочесть растр из файла?
    #36635868
Фотография Бенедикт
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
litvin44,

Можно (в смысле, один из способов) воспользоваться стандартными функциями SavePicture() и LoadPicture(). Для этого надо завернуть GDI-ный битмап в COM-объект, поддерживающий интерфейс IPictureDisp, см. здесь функцию CreateIPictureDispFromHBITMAP().
Соответственно, запись:
Код: plaintext
SavePicture CreateIPictureDispFromHBITMAP(hBM,  0 ,  0 ), путь
Чтение:
Код: plaintext
Dim Pic As IPictureDisp\nSet Pic = LoadPicture(путь)
, после чего Pic.Handle имеет значение дескриптора битмапа. Отрисовка на целевом DC через Pic.Render, или объект.PaintPicture(), или BitBlt(). Либо можно сделать просто Set Picture1.Picture = Pic.
...
Рейтинг: 0 / 0
Как записать растр в файл? Как прочесть растр из файла?
    #36640416
litvin44
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Бенедикт,

Спасибо за подсказку.

К сожалению, CreateIPictureDispFromHBITMAP() не работает так как:
- не подключена библиотека Lib "olepro32" – где ее взять?
- что за тип PICTYPE (входит в структуру PicBmp)?

Зато фраза "Pic.Handle имеет значение дескриптора битмапа" оказалась ключевой.

С чтением проблема снята:
Dim hDC As Long, Pic As IPictureDisp
Set Pic = LoadPicture(путь)
SelectObject hDC, Pic.Handle

Потом можно что-то нарисовать на hDC, и сохранить с помощью
SavePicture Pic, путь

Но, для того, что бы сохранить, сначала приходится прочесть файл с картиной нужных ширины и высоты.
А создать Pic "с нуля" не получается
...
Рейтинг: 0 / 0
Как записать растр в файл? Как прочесть растр из файла?
    #36640548
Фотография Бенедикт
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
litvin44К сожалению, CreateIPictureDispFromHBITMAP() не работает так как:
- не подключена библиотека Lib "olepro32" – где ее взять?
- что за тип PICTYPE (входит в структуру PicBmp)?1) Что значит "не работает"? Подробности.
2) Что значит "не подключена"? olepro32.dll входит в состав ОС. Это не ActiveX-библиотека, её не надо регистрировать или подключать в диалоге References. Если её нет в системной папке (WINDOWS\System32), с системой что-то не в порядке.
3) Перечислимый тип PICTYPE описан в том же коде.litvin44С чтением проблема снята:
Dim hDC As Long, Pic As IPictureDisp
Set Pic = LoadPicture(путь)
SelectObject hDC, Pic.Handle

Потом можно что-то нарисовать на hDC, и сохранить с помощью
SavePicture Pic, путьНу, можно, конечно, и сразу SelectObject() делать... Это короткий путь, Вы сами наткнулись, на то к чему он приводит. (Кстати, Вы что, опять (вспоминая прошлую тему) игнорируете утечку ресурсов, не запоминая старый HBITMAP?) Но лучше этого не делать и рисовать IPictureDisp на hDC, вызывая метод IPictureDisp.Render(), он, например, прозрачность понимает (для поддерживаемых форматов).litvin44Но, для того, что бы сохранить, сначала приходится прочесть файл с картиной нужных ширины и высоты.
А создать Pic "с нуля" не получаетсяСоздаёте (как сами и показали в первом сообщении!) новый битмап через CreateCompatibleBitmap(), выбираете в контексте устройства, запоминая попутно старый, рисуете сцену, восстанавливаете старый битмап, далее скармливаете (новый) битмап функции CreateIPictureDispFromHBITMAP(), далее вызываете SavePicture().

Посмотрите, кстати, описание OleCreatePictureIndirect(), разберитесь с её третьим параметром (он же третий параметр CreateIPictureDispFromHBITMAP()). Он определяет, когда и кем будет уничтожен битмап.
...
Рейтинг: 0 / 0
Как записать растр в файл? Как прочесть растр из файла?
    #36640559
Фотография Бенедикт
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
litvin44,

взяв пример из темы по ссылке:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
Option Explicit

Private Declare Function CreateCompatibleDC Lib "gdi32" ( _
   ByVal hDC As Long) As Long
Private Declare Function CreateCompatibleBitmap Lib "gdi32" ( _
   ByVal hDC As Long, ByVal nWidth As Long, ByVal nHeight As Long) As Long
Private Declare Function DeleteDC Lib "gdi32" ( _
   ByVal hDC As Long) As Long

Private Declare Function SelectObject Lib "gdi32" ( _
   ByVal hDC As Long, ByVal hObject As Long) As Long
'Private Declare Function DeleteObject Lib "gdi32" ( _
'   ByVal hObject As Long) As Long

Private Declare Function SetPixel Lib "gdi32" ( _
   ByVal hDC As Long, ByVal x As Long, ByVal y As Long, _
   ByVal crColor As Long) As Long

Private Sub Command1_Click()
 Dim hbmMem As Long
 Dim hdcMem As Long
 Dim hbmOld As Long
 Dim picSrc As IPictureDisp
 Dim cxSrc As Long, cySrc As Long
 
 Set picSrc = LoadPicture("C:\Temp\src.bmp")
 cxSrc = Picture1.ScaleX(picSrc.Width, vbHimetric, vbPixels)
 cySrc = Picture1.ScaleY(picSrc.Height, vbHimetric, vbPixels)
 
 hbmMem = CreateCompatibleBitmap(Picture1.hDC, cxSrc, cySrc)
 If hbmMem =  0  Then Exit Sub
 hdcMem = CreateCompatibleDC(Picture1.hDC)
 hbmOld = SelectObject(hdcMem, hbmMem)
 
 'Под Win9x следует почистить битмап, нарисовав чёрный прямоугольник

 'Особенность вызова метода Render: надо убедиться, что параметры передаются
 'по значению. Если не уверены, используйте CLng(параметр).
 picSrc.Render (hdcMem),  0 &,  0 &, (cxSrc), (cySrc), _
                0 &, picSrc.Height, picSrc.Width, -picSrc.Height, ByVal  0 &
 Set picSrc = Nothing
 
 SetPixel hdcMem,  10 ,  20 , RGB( 255 ,  0 ,  0 )
 SetPixel hdcMem,  20 ,  40 , RGB( 0 ,  255 ,  0 )
 SetPixel hdcMem,  10 ,  40 , RGB( 0 ,  0 ,  255 )
 
 SelectObject hdcMem, hbmOld
 DeleteDC hdcMem
 
' Set Picture1.Picture = CreateIPictureDispFromHBITMAP(hbmMem)
 SavePicture CreateIPictureDispFromHBITMAP(hbmMem), "C:\Temp\dst.bmp"
End Sub
...
Рейтинг: 0 / 0
Как записать растр в файл? Как прочесть растр из файла?
    #36641957
litvin44
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Бенедикт,

1) Не работает в смысле VB-5 (который используется на работе, чтоб избежать проблем с ОБЭП) дает сообщение: Private Enum types cannot be used as parameter or return types for public procedures, or as public data members
В VB-6 работает

2) "разберитесь с её третьим параметром" – не понял.
Это как-то связано с тем, что hbmMem НЕ удаляется в вашем примере?

3) Пожалуйста, объясните мне про удаление, и, заодно, проверьте код.

Вариант 1 (по вашим рекомендациям):
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
Sub zz01()
Dim hGetDC As Long, hBM As Long, hDC As Long, hbmOld As Long
Dim IPD As IPictureDisp
    'создание устройства и растра
    hGetDC = GetDC( 0 )
    hBM = CreateCompatibleBitmap(hGetDC,  100 ,  100 )
    ReleaseDC  0 , hGetDC
    hDC = CreateCompatibleDC( 0 )
    hbmOld = SelectObject(hDC, hBM)
    'рисование
    SetPixel hDC,  10 ,  10 ,  255 
    'в файл
    Set IPD = CreateIPictureDispFromHBITMAP(hBM)
    SavePicture IPD, "c:\00\123.bmp"
    'удаление
    SelectObject hDC, hbmOld
    DeleteDC hDC
End Sub

Вариант 2 (свой):
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
Sub zz02()
Dim hGetDC As Long, hBM As Long, hDC As Long
Dim IPD As IPictureDisp
    'создание устройства и растра
    hGetDC = GetDC( 0 )
    hBM = CreateCompatibleBitmap(hGetDC,  100 ,  100 )
    ReleaseDC  0 , hGetDC
    hDC = CreateCompatibleDC( 0 )
    SelectObject hDC, hBM
    'рисование
    SetPixel hDC,  90 ,  90 ,  255 
    'в файл
    Set IPD = CreateIPictureDispFromHBITMAP(hBM)
    SavePicture IPD, "c:\00\123.bmp"
    'удаление
    DeleteDC hDC
    DeleteObject hBM
End Sub
Работают оба, но меня настораживает то, что если опустить
Код: plaintext
1.
    Set IPD = CreateIPictureDispFromHBITMAP(hBM)
    SavePicture IPD, "c:\00\123.bmp"
в самый конец кода, после удаления, в вар.1, то срабатывает, т.е. hBM НЕ очищено
А в вар.2 выдает ошибку, что логично, т.к. hBM уже удалено
...
Рейтинг: 0 / 0
Как записать растр в файл? Как прочесть растр из файла?
    #36642376
Фотография Бенедикт
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
litvin441) Не работает в смысле VB-5 (который используется на работе, чтоб избежать проблем с ОБЭП) дает сообщение: Private Enum types cannot be used as parameter or return types for public procedures, or as public data members
В VB-6 работаетСтранно, там и типы private, и функция объявлена с private. Можно вместо As PICTYPE написать As Long и забыть.litvin442) "разберитесь с её третьим параметром" – не понял.
Это как-то связано с тем, что hbmMem НЕ удаляется в вашем примере?Да.litvin443) Пожалуйста, объясните мне про удаление,Если флаг fPictureOwnsHandle равен 0, дескриптор битмапа удаляете сами, и сами следите, чтобы не было к возвращённому COM-объекту обращения, ожидающего, что в объекте что-то есть. Если флаг не равен 0, COM-объект сам решает, когда удалить битмап (точнее, GDI-объект, т. к. это может быть не только битмап). Если количество ссылок на объект становится равным 0, битмап удаляется. Т.е. время жизни битмапа не превышает время жизни COM-объекта, и, например, если переменная, содержащая ссылку на него, вышла за область видимости, счётчик ссылок внутри объекта уменьшается на 1, если он при этом стал равным 0 - см. выше. Т.о., о DeleteObject(), особенно если битмап используется в нескольких местах, голова не болит.litvin44и, заодно, проверьте код.

Вариант 1 (по вашим рекомендациям):
...С виду правильно. Я бы (чистая вкусовщина) код "удаление" поменял местами с "в файл".litvin44Вариант 2 (свой):
...
Код: plaintext
1.
2.
SelectObject hDC, hBM
...
DeleteObject hBM
Это как скобки в математическом выражении, или как операторные скобки в языке программирования: открыл-закрой! Результат SelectObject() надо сохранять (старый битмап), и восстанавливать, даже (или прямо) перед DeleteDC(). Иначе-утечка ресурса.litvin44Работают оба, но меня настораживает то, что если опустить
Код: plaintext
1.
    Set IPD = CreateIPictureDispFromHBITMAP(hBM)
    SavePicture IPD, "c:\00\123.bmp"
в самый конец кода, после удаления, в вар.1, то срабатывает, т.е. hBM НЕ очищеноПоскольку при вызове CreateIPictureDispFromHBITMAP() параметр fPictureOwnsHandle был опущен, его значение было взято по умолчанию 1. Таким образом, за время жизни битмапа с дескриптором hBM отвечает объект, на который ссылается IPD. Как только IPD выходит за область видимости при достижении End Sub, счётчик ссылок уменьшается до 0, объект в своём деструкторе делает DeleteObject().
litvin44А в вар.2 выдает ошибку, что логично, т.к. hBM уже удаленоЛогично.
...
Рейтинг: 0 / 0
Как записать растр в файл? Как прочесть растр из файла?
    #36642676
litvin44
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Бенедикт,

«Можно вместо As PICTYPE написать As Long и забыть.» - не работает.
После этого начинает ругаться на OleCreatePictureIndirect
(Именно по этому я ошибочно написал во 2-м посте, что «не подключена библиотека Lib "olepro32" – где ее взять?» - не разобравшись, подумал, что декларация не правильная, а API-View такой функции не показывает)

Мне трудно с вами спорить, как с НАМНОГО более квалифицированным, но имхо, как раз во 2-м варианте соблюдено «открытие/закрытие скобок»
SelectObject сам по себе уничтожает прошлый объект (или нет?)
В 1-м варианте это уничнотжение hBM срокой SelectObject hDC, hbmOld (при этом, непонятно, куда девается hbmOld)
Во 2-м это явное уничтожение DeleteObject hBM строкой DeleteObject hBM (без ожидания, когда это сделает CreateIPictureDispFromHBITMAP).

Кстати, напишите, пожалуйста, что означают параметры CreateIPictureDispFromHBITMAP и как их применять – сам я не разберусь.

Личный вопрос: а как вы запомнили мою прошлую тему?
И (набрался наглости) как у вас проконсультироваться в будущем?
Дело в том, что я НЕ программист, но надо работать в VBA (сейчас в CorelDraw) а он сильно урезанный по сравнению с VB, вот и приходится идти окольными тропами.
...
Рейтинг: 0 / 0
Как записать растр в файл? Как прочесть растр из файла?
    #36645176
Фотография Бенедикт
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
litvin44«Можно вместо As PICTYPE написать As Long и забыть.» - не работает.
После этого начинает ругаться на OleCreatePictureIndirect
(Именно по этому я ошибочно написал во 2-м посте, что «не подключена библиотека Lib "olepro32" – где ее взять?» - не разобравшись, подумал, что декларация не правильная, а API-View такой функции не показывает)У меня нет VB 5, чтобы посмотреть. Проверьте, что в проект подключена библиотека типов OLE Automation, что код помещён в общем модуле (не модуле класса/формы), что все UDT и Declare описаны как Private.litvin44имхо, как раз во 2-м варианте соблюдено «открытие/закрытие скобок»
SelectObject сам по себе уничтожает прошлый объект (или нет?)Нет. Это было бы странно - я нарисовал что-то в контексте устройства на битмапе, хочу сменить битмап, и нарисовать что-то другое, а SelectObject() взяла бы и убила первый битмап. Для этого есть DeleteObject(). Обратите внимание на описание SelectObject() :MSDN Library, SelectObject FunctionThis function returns the previously selected object of the specified type. An application should always replace a new object with the original, default object after it has finished drawing with the new object.
litvin44В 1-м варианте это уничнотжение hBM срокой SelectObject hDC, hbmOld (при этом, непонятно, куда девается hbmOld)Не уничтожение, а выбор исходного объекта данного типа (битмап). hbmOld будет "убит" в DeleteDC(), совместно с другими ресурсами (кистями, шрифтами, регионами и т. д.). Я в отладочном коде, бывает, пишу SelectObject hDC, hbmOld: hbmOld = 0, чтобы 1) показать, что судьба этого объекта меня не интересует, за него теперь отвечает система; 2) случайно не воспользоваться значением этого дескриптора; 3) при отладке в окне локальных переменных видеть потенциально не освобождённые ресурсы (дескрипторы, не равные 0). hBM же уничтожается при уменьшении ссылок на COM-объект, в который завёрнут hBM, до 0, в данном случае при достижении End Sub. Можно явно уменьшить количество ссылок: Set IPD = Nothing.litvin44Во 2-м это явное уничтожение DeleteObject hBM строкой DeleteObject hBM (без ожидания, когда это сделает CreateIPictureDispFromHBITMAP).Хотите явно уничтожать битмап вызовом DeleteObject(), вызывайте CreateIPictureDispFromHBITMAP с параметрами (hBM, 0, 0). CreateIPictureDispFromHBITMAP() не уничтожает битмап, а заворачивает его в COM-объект и возвращает на него ссылку.litvin44Кстати, напишите, пожалуйста, что означают параметры CreateIPictureDispFromHBITMAP и как их применять – сам я не разберусь.Первый параметр - дескриптор битмапа, второй параметр - дескриптор палитры (может понадобиться если битмап создаётся совместимым с устройством с глубиной цвета 8 и менее бит, ныне это редкий случай, обычно, и по умолчанию, этот параметр равен 0), третий параметр - если 0, DeleteObject() делаете сами, если не 0 (по умолчанию), DeleteObject() делает возвращаемый функцией COM-объект.litvin44Личный вопрос: а как вы запомнили мою прошлую тему?Показалась знакомой комбинация тематики и участника форума, посмотрел в профиль участника.litvin44И (набрался наглости) как у вас проконсультироваться в будущем?Пишите в форум, если считаете, что тема имеет шанс кому-то ещё пригодиться в дальнейшем, пишите на адрес в моём профиле, если такого шанса нет, иле не хотите выносить тему на общее обозрение. Но почту я читаю реже форума.litvin44Дело в том, что я НЕ программист, но надо работать в VBA (сейчас в CorelDraw) а он сильно урезанный по сравнению с VB, вот и приходится идти окольными тропами.Насколько я понимаю, CorelDraw обычный VBA-хост, по языку не урезан, а стандартно подключаемые в проект библиотеки свои. По библиотекам не скажу, а то, что решается языком и внешними библиотеками, в любых VBA-хостах должно работать одинаково. А системные API - это вполне прямые тропы, по ним хоть документацию можно найти и примеры. Но кода, да, больше.
...
Рейтинг: 0 / 0
9 сообщений из 9, страница 1 из 1
Форумы / Visual Basic [игнор отключен] [закрыт для гостей] / Как записать растр в файл? Как прочесть растр из файла?
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]