Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Начинающим";
Текущий архив: 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.043 c
2-1190627006
misha_gr
2007-09-24 13:43
2007.10.21
TClientDataSet.Locate


15-1190197815
Sergey13
2007-09-19 14:30
2007.10.21
Сегодня самый известный сетевой символ — смайлик — отмечает юбиле


4-1177198354
nikitozz
2007-04-22 03:32
2007.10.21
Как завершить процесс.


2-1190363813
Flood_control
2007-09-21 12:36
2007.10.21
Edit & UpDown


11-1174343845
finder2007
2007-03-20 01:37
2007.10.21
Как сортировать узлы в TreeView ?





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский