Форум: "Начинающим";
Текущий архив: 2007.10.21;
Скачать: [xml.tar.bz2];
ВнизРазница между методом копирования Assign и загрузки BMP в TImage Найти похожие ветки
← →
Vasiliy (2007-09-29 20:17) [0]Доброго времени суток, уважаемые мастера.
Мне хотелось чтобы кто нибудь помог мне разобраться в идеологическом аспекте вопроса.
Потому как у самого вряд ли получится без сторонней поддержки.
Итак, есть небольшой код в котором вывожу на печать через объект TPrinter изображение из компонента Image.
Казалось бы все нормально и можно было бы забыть, мол печатает ну ладно, по принципу результат есть. Но меня
честно говоря мучают сомнения. По сути основных в данном коде являются 3 строки:
Bitmap.SaveToFile("ToPrinter.bmp");
Bufferimage.Picture.LoadFromFile("ToPrinter.bmp");
deletefile("ToPrinter.bmp");
Где я записываю на диск сохраненное изображение в Bitmap в формате *.bmp. После чего я его считываю и отправляю
на печать. Так вот, когда я пытался использовать полное копирование из Bitmap в BufferImage (тоже глобыльный компонент
Timage) методом Assign (так как при выполнении этого метода происходит полное копирование одного объекта
в другой) ПЕЧАТИ НА ПРИНТЕР НЕ БЫЛО. Хотя в BufferImage изображение формата Bitmap было и я мог с ним делать и выполнять
любые операции. Долго я мучался,пока не нашел такой (мне так кажется) кривоватый способ, но который работает.
Так вот вопрос заключается в том, какая разница между загруженным с диска картинкой BMP в компонент TImage, от
той же загрузки из другого компонента TImage методом Assign.
Может есть какая то разница в их предсталении или способе размещения в памяти.Ведь в одном случае печать работает
а в другом хоть убейся не идет. Может создатели Дельфи упустили чего при создании своего продукта.
Я ответ не знаю, может Вы мне поможете разобраться, уважаемые Мастера.
С уважением, Василий.
А вот сам код:
procedure TFrmMain.ToPrinterClick(Sender: TObject);
var
Bitmap: TBitmap;
procedure PrintImage(Image: TImage; ZoomPercent: Integer);
// if ZoomPercent=100, Image will be printed across the whole page
var
relHeight, relWidth: integer;
begin
Screen.Cursor := crHourglass;
Printer.BeginDoc;
with Image.Picture.Bitmap do
begin
if ((Width / Height) > (Printer.PageWidth / Printer.PageHeight)) then
begin
// Stretch Bitmap to width of PrinterPage
relWidth := Printer.PageWidth;
relHeight := MulDiv(Height, Printer.PageWidth, Width);
end
else
begin
// Stretch Bitmap to height of PrinterPage
relWidth := MulDiv(Width, Printer.PageHeight, Height);
relHeight := Printer.PageHeight;
end;
relWidth := Round(relWidth * ZoomPercent / 100);
relHeight := Round(relHeight * ZoomPercent / 100);
Printer.Canvas.StretchDraw(Rect(0, 0, relWidth, relHeight),Image.Picture.Graphic);
end;
Printer.EndDoc;
Screen.cursor := crDefault;
end;
begin // main procedure
case Main_PageControl.TabIndex of
0: Region:=Tahh; // глобальная перечислимая переменная
1: ........;
2: ........;
3: ........;
end;
Bitmap := TBitmap.Create;
case Region of
Tahh : Begin
Bitmap.Height := Tah_CHS.Height;
Bitmap.Width := Tah_CHS.Width;
Bitmap.Canvas.Draw(0,0,Tah_CHS.Picture.Bitmap);
end;
.....// присваивание Bitmap"у значений аналогично приведенного в Tahh
end; //case Region of
Screen.Cursor := crHourglass;
Bitmap.SaveToFile("ToPrinter.bmp");
Bufferimage.Picture.LoadFromFile("ToPrinter.bmp");
deletefile("ToPrinter.bmp");
Screen.cursor := crDefault;
Bitmap.free;
if MainFRM_Prnt.Execute then begin
// Print image at 100% zoom:
PrintImage(Bufferimage, 100);
end;
end; // end prosedure TFrmMain.ToPrinterClick(Sender: TObject);
← →
Однокамушкин (2007-09-29 22:03) [1]TBitmap может хранить картинку в двух форматах - DDB (device dependent bitmap) и DIB (device independent bitmap), первый из этих форматов привязан к формату данных, принятому в конкретном устройстве вывода, второй не привязан ни к одному устройству... По умолчанию TBitmap создаёт DDB-растр, привязанный к дисплею, поэтому корректное отображение такой картинки гарантируется только на дисплее, а на принтере и других устройствах - это как повезёт... При сохранении растра в поток он в любом случае сохраняется как DIB, поэтому при последующей загрузке тоже получается формат DIB, а этот формат правильно отображается на любом устройстве... Точнее, при загрузке может получиться DDB, но только в том случае, если переменная Graphics.DDBsOnly равна True, а по умолчанию она равна False (кстати, в справке написано, что когда эта переменная равна False, то вновь создаваемые растры имеют формат DIB, но вы этому не верьте, там в коде VCL ошибка, поэтому будет DDB независимо от значения этой переменной)
Таким образом, при выполнении Assign ваша картинка сохраняет формат DDB, потому что копируется как есть, а при записи в файл и чтении из него меняет формат на DIB, который нормально печатается. Чтобы преобразовать DDB к DIB, можно воспользоваться свойством TBitmap.HandleType - измените его на bmDIB, и ваша картинка поменяет формат и будет корректно распечатываться
← →
Vasiliy (2007-09-30 20:16) [2]Однокамушкин (29.09.07 22:03) [1].
Спасибо.
Маленький вопрос. Когда оптимально переводить объект TBitmap в режим bmDIB.
Сразу после действия Create или после копирования в него изображения.
С уважением.
← →
Однокамушкин (2007-09-30 21:00) [3]Лучше сразу после Create, до задания значений свойств Width и Heigth, чтобы время на конвертацию не тратилось, а сразу всё рисовалось как DIB
← →
Vasiliy (2007-09-30 21:08) [4]Огромное спасибо.
Теперь то точно буду знать.
А нет ли какой нибудь ссылки на ресурс где можно было бы полностью почитать про работу с изображениями?
← →
Dib@zol © (2007-09-30 21:13) [5]Совсем обнаглел ;))
http://www.google.ru/search?hl=ru&newwindow=1&q="Работа%20с%20изображениями"AND%20Delphi&lr=
Вот. Туча всего по работе с изображениями.
← →
Vasiliy (2007-09-30 21:24) [6]Неа, не обнаглел :)))
Просто благодаря "Однокамушкин (29.09.07 22:03) [1]" я понял в чем проблема, хотя в литературе, которая у меня есть ни слова об этом.
Кстати, есть еще один вопрос, но уже немного не в той теме.
Оно связано с работой в цикле for to do.
А смысл в чем. Когда я работал с присваиванием данных в массивы, ипользовав при этом комбинацию for z:=1 to N, обратил внимание что компилятор отсчитывает обратным путем от N->>1.
То есть получается что по логике вещей надо от 1 до N, а на приктике получается наоборот. Тоже долго думал почему у меня были ошибки в проге, пока не увидел эту особенность.
Это специально так сделано создателями, или проще вести цикл от конца к началу с точки зрения представления его в компьютере.
С уважением.
← →
homm © (2007-09-30 21:32) [7]> обратил внимание что компилятор отсчитывает обратным путем от N->>1.
Надеюсь Вы сечас покраснели :)
← →
Vasiliy (2007-09-30 21:40) [8]Зачем краснеть, если это так и есть. :)))
Так меня самого в ступор эта ситуация вогнала вначале. :))
Увидел это, когда пошагово программу выполнял, чтобы отловить причину ошибки.
Попробуйте и сами убедитесь.
С уважением :)))
← →
homm © (2007-09-30 21:47) [9]
var
nums: array [0..9] of Integer;
begin
for i := 0 to 9 do
nums[i] := i;
end;
Вот незамысловатый код. Ставлю точку останова, шелкаю с контролом по nums, и смотрю как на каждом шаге каждому следующему элементу присваивается значение. Счетчик действительно удобнее считать наоборот, причем дельфи иногда так и делает, причем если своббодно 2 регистра, организовывается 2 счетсика, один в обратном напрвлении, для собственно подсчета, другой просто инкрементируется на каждом шаге и сам уже используется в теле цикла. Но убедить меня в том, что компилятор делает что-то не так, и от его внутренней организации на уровне команд зависти логика алгорита, Вы не сможете.
← →
Desdechado © (2007-09-30 21:52) [10]Отсчет идет от большего к меньшему, если внутри цикла от этого ничего не зависит.
← →
Vasiliy (2007-09-30 21:59) [11]Да я не про логику. Она нормальна, коли работает :))
Просто я вышел на это когда работал с крупными структурными массивами и необходимо было выполнять некоторые арифметические действия над элементами в них.
И оказывалось, что где то в конце пока не заполненый i,j элемент при выполнении определенной операции над ним давал ошибку. Хотя по структуре программы (если бы все шло по счетчику как полагается от меньшего к большему)ошибки не должно было бы быть. И получается что при писании кода и это надо учитывать.
Когда обращался к программистам в живую, мне ответили "Ну работает и работает, тебе то что. Переделай программу как надо". Так или иначе я сделал преобразования, но мне остался непонятен смысл подобной работы программы.
← →
homm © (2007-09-30 22:02) [12]> операции над ним давал ошибку.
Это была Ваша ошибка.
> Хотя по структуре программы (если бы все шло по счетчику
> как полагается от меньшего к большему)ошибки не должно было
> бы быть.
Такого не может быть, всчетчик для программиста всегда идет так, как он написан в исходном коде, от внутренней организации ничего не зависит.
> И получается что при писании кода и это надо учитывать.
Не нужно.
← →
Vasiliy (2007-09-30 22:14) [13]>>>homm © (30.09.07 22:02) [12]
Не совсем согласен.
К сожалению старые исходники стер. Показал бы код на примере.
Но все же это редкость но есть, если у вас элемент массива в конце будет не заполненный или пустой, то при обратном обращении компилятора к нему при выполнении определенного действия над нам выскочит ошибка (точно не помню) что то связанное с памятью. У меня это было, врать смысла нету.
← →
Anatoly Podgoretsky © (2007-09-30 22:16) [14]> Vasiliy (30.09.2007 21:59:11) [11]
> И оказывалось, что где то в конце пока не заполненый i,j элемент при выполнении определенной операции над ним давал ошибку.
Это твоя ошибка, такого быть не должно.
← →
homm © (2007-09-30 22:17) [15]> [13] Vasiliy (30.09.07 22:14)
> Показал бы код на примере.
Пока нет примера описанного явления, я думаю что это все-же заблуждение.
← →
Vasiliy (2007-09-30 22:18) [16]>>>Desdechado © (30.09.07 21:52) [10]
Отсчет идет от большего к меньшему, если внутри цикла от этого ничего не зависит.
Тогда стоит еще более интересный вопрос, а зачем это нужно? Ради чего?
← →
homm © (2007-09-30 22:22) [17]> [16] Vasiliy (30.09.07 22:18)
> Ради чего?
Ради того, что есть 1 инструкция loop, которая делает двойную работу, одновременно срванивает значение регистра с нулем, и в случае неравенства переносит по указанному адресу.
← →
Vasiliy (2007-09-30 22:29) [18]К сожалению в asm я "0", но кое что вроде понимать начинаю.
Но все равно покопаюсь, может найду старый код на работе, чтобы более детально рассмотреть вопрос.
Но так или иначе очень интересная ситуация.
Страницы: 1 вся ветка
Форум: "Начинающим";
Текущий архив: 2007.10.21;
Скачать: [xml.tar.bz2];
Память: 0.51 MB
Время: 0.063 c