Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2007.10.21;
Скачать: CL | DM;

Вниз

Разница между методом копирования 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;
Скачать: CL | DM;

Наверх




Память: 0.53 MB
Время: 0.019 c
1-1186377350
Berkut
2007-08-06 09:15
2007.10.21
Передеча форматированного текста в Word


2-1191175017
Pacific
2007-09-30 21:56
2007.10.21
WebBrowser1


15-1189456500
Суслик
2007-09-11 00:35
2007.10.21
Бесплатный семинар по продуктам Delphi 2007, C++ Builder 2007


15-1190138260
Mozart
2007-09-18 21:57
2007.10.21
знатели Exchange!!! ПОМОГИТЕ!!!!


15-1190158063
Riply
2007-09-19 03:27
2007.10.21
Монитор и зрение