Printer.Canvas.DrawRect
От: KaBoom Чехия  
Дата: 28.05.14 11:12
Оценка:
Преамбула: Для формирования некоего документа, состоящего из текстов и картинок (например этикетки на посылке) используются объекты VCL — TLabel и TImage. Написан специальный конструктор, в котором в стиле Delphi IDE можно нарисовать шаблон любой конфигурации для печати различных этикеток, и затем сохранить его в БД в виде XML (содержимое картинки переводится в строку). При печати этикетки все объекты шаблона рисуют себя на холсте (Canvas) принтера. Все работает отлично, за исключением одной маленькой проблемы — рандомно (зависимость отследить не удалось) TImage вместо картинки рисует черный прямоугольник. Причем не обязательно это должен быть канвас принтера, на форме тоже иногда бывает. Есть какие-нибудь идеи, как это побороть? Для отрисовки используются функции Canvas.CopyRect, Canvas.StretchDraw — результат один и тот же. Хелп!
Re: Printer.Canvas.DrawRect
От: Softwarer http://softwarer.ru
Дата: 28.05.14 11:33
Оценка:
Здравствуйте, KaBoom, Вы писали:

KB> рандомно (зависимость отследить не удалось) TImage вместо картинки рисует черный прямоугольник


Сделайте функцию, которая сразу после отрисовки проверяет канвас на "чёрный прямоугольник". Там брейкпоинт на положительное срабатывание, или отладочную печать... в общем, ловите ситуацию.
Re: Printer.Canvas.DrawRect
От: Aniskin  
Дата: 28.05.14 12:02
Оценка:
Здравствуйте, KaBoom, Вы писали:

KB>При печати этикетки все объекты шаблона рисуют себя на холсте (Canvas) принтера.


Как это реализовано?
Re[2]: Printer.Canvas.DrawRect
От: KaBoom Чехия  
Дата: 28.05.14 13:01
Оценка:
Здравствуйте, Aniskin, Вы писали:

A>Здравствуйте, KaBoom, Вы писали:


KB>>При печати этикетки все объекты шаблона рисуют себя на холсте (Canvas) принтера.


A>Как это реализовано?



procedure TfmTemplate.PrintObjects(ACanvas: TCanvas);
var
   i: Integer;
begin    
   for i := 0 to Pred(ComponentCount) do
   begin
      if Components[i].ClassType = TTicketRotateImage   then TTicketRotateImage(Components[i]).DrawOnCanvas(ACanvas);
      if Components[i].ClassType = TTicketStaticImage   then TTicketStaticImage(Components[i]).DrawOnCanvas(ACanvas);
      if Components[i].ClassType = TTicketLabel         then TTicketLabel(Components[i]).DrawOnCanvas(ACanvas);
      if Components[i].ClassType = TTicketBarcode       then TTicketBarcode(Components[i]).DrawOnCanvas(ACanvas);
   end;
end;


procedure TfmTemplate.Print;
begin
   Printer.BeginDoc;
   PrintObjects(Printer.Canvas);
   Printer.EndDoc;
end;


З.ы.: С интерфейсами не стал заморачиваться, поскольку объектов всего 4 типа и новых не предвидится
Re[3]: Printer.Canvas.DrawRect
От: BlackEric http://black-eric.lj.ru
Дата: 28.05.14 13:46
Оценка:
Здравствуйте, KaBoom, Вы писали:

A>>Как это реализовано?


KB>
KB>procedure TfmTemplate.PrintObjects(ACanvas: TCanvas);
KB>var
KB>   i: Integer;
KB>begin    
KB>   for i := 0 to Pred(ComponentCount) do
KB>   begin
KB>      if Components[i].ClassType = TTicketRotateImage   then TTicketRotateImage(Components[i]).DrawOnCanvas(ACanvas);
KB>      if Components[i].ClassType = TTicketStaticImage   then TTicketStaticImage(Components[i]).DrawOnCanvas(ACanvas);
KB>      if Components[i].ClassType = TTicketLabel         then TTicketLabel(Components[i]).DrawOnCanvas(ACanvas);
KB>      if Components[i].ClassType = TTicketBarcode       then TTicketBarcode(Components[i]).DrawOnCanvas(ACanvas);
KB>   end;
KB>end;


KB>procedure TfmTemplate.Print;
KB>begin
KB>   Printer.BeginDoc;
KB>   PrintObjects(Printer.Canvas);
KB>   Printer.EndDoc;
KB>end;
KB>


Вставляйте запись в лог после каждой строки и смотрите что произошло. За несколько итераций отловите.
https://github.com/BlackEric001
Re[3]: Printer.Canvas.DrawRect
От: Aniskin  
Дата: 28.05.14 18:15
Оценка:
Здравствуйте, KaBoom, Вы писали:

KB> if Components[i].ClassType = TTicketRotateImage then TTicketRotateImage(Components[i]).DrawOnCanvas(ACanvas);

KB> if Components[i].ClassType = TTicketStaticImage then TTicketStaticImage(Components[i]).DrawOnCanvas(ACanvas);
KB> if Components[i].ClassType = TTicketLabel then TTicketLabel(Components[i]).DrawOnCanvas(ACanvas);
KB> if Components[i].ClassType = TTicketBarcode then TTicketBarcode(Components[i]).DrawOnCanvas(ACanvas);

Еще бы глянуть код той процедуры DrawOnCanvas, в которой периодически рисуется черный прямоугольник.
Re[4]: Printer.Canvas.DrawRect
От: KaBoom Чехия  
Дата: 29.05.14 07:43
Оценка:
Здравствуйте, Aniskin, Вы писали:

A>Еще бы глянуть код той процедуры DrawOnCanvas, в которой периодически рисуется черный прямоугольник.



procedure TTicketStaticImage.DrawOnCanvas(ACanvas: TCanvas);
var
  RLeft, RTop, RRight, RBottom: Integer;
begin
   RLeft   := Left;
   RTop    := Top;
   RRight  := RLeft+Width;
   RBottom := RTop+Height;


   RLeft   := Floor(RLeft   * HorizontalScale);
   RTop    := Floor(RTop    * VerticalScale);
   RRight  := Floor(RRight  * HorizontalScale);
   RBottom := Floor(RBottom * VerticalScale);
   ACanvas.CopyRect(Rect(RLeft, RTop, RRight, RBottom), Picture.Bitmap.Canvas, Rect(0,0,Picture.Bitmap.Width, Picture.Bitmap.Height));

   //ACanvas.StretchDraw(Rect(RLeft, RTop, RRight, RBottom), Picture.Bitmap);
end;


HorizontalScale и VerticalScale это множители для пересчета экранных координат в координаты принтера, определяются один раз в начале работы:


procedure InitScales;
begin
   HorizontalScale := GetDeviceCaps(Printer.Handle, LOGPIXELSX) / GetDeviceCaps(GetDC(0), LOGPIXELSX);
   VerticalScale   := GetDeviceCaps(Printer.Handle, LOGPIXELSY) / GetDeviceCaps(GetDC(0), LOGPIXELSY);
end;
Re[5]: Printer.Canvas.DrawRect
От: Aniskin  
Дата: 29.05.14 09:12
Оценка:
Здравствуйте, KaBoom, Вы писали:

Версия Delphi? Печать в основном потоке? Во время печати нет дополнительных работающих потоков, работающих с TCanvas?
Re[6]: Printer.Canvas.DrawRect
От: KaBoom Чехия  
Дата: 29.05.14 09:30
Оценка:
Здравствуйте, Aniskin, Вы писали:

A>Здравствуйте, KaBoom, Вы писали:


A>Версия Delphi? Печать в основном потоке? Во время печати нет дополнительных работающих потоков, работающих с TCanvas?


Delphi 7, печать в основном потоке, больше никто с Canvas не работает
Re: Printer.Canvas.DrawRect
От: Danchik Украина  
Дата: 29.05.14 10:35
Оценка:
Здравствуйте, KaBoom, Вы писали:

KB>Преамбула: Для формирования некоего документа, состоящего из текстов и картинок (например этикетки на посылке) используются объекты VCL — TLabel и TImage. Написан специальный конструктор, в котором в стиле Delphi IDE можно нарисовать шаблон любой конфигурации для печати различных этикеток, и затем сохранить его в БД в виде XML (содержимое картинки переводится в строку). При печати этикетки все объекты шаблона рисуют себя на холсте (Canvas) принтера. Все работает отлично, за исключением одной маленькой проблемы — рандомно (зависимость отследить не удалось) TImage вместо картинки рисует черный прямоугольник. Причем не обязательно это должен быть канвас принтера, на форме тоже иногда бывает. Есть какие-нибудь идеи, как это побороть? Для отрисовки используются функции Canvas.CopyRect, Canvas.StretchDraw — результат один и тот же. Хелп!


Появилась мысль что где-то у вас есть утечка графических ресурсов, и в какой-то момент это приводит к неработоспособности системы.
Например попробуйте эту тулзу http://www.nirsoft.net/utils/gdi_handles.html (нашел первое попавшееся)
Re[2]: Printer.Canvas.DrawRect
От: KaBoom Чехия  
Дата: 29.05.14 10:58
Оценка:
Здравствуйте, Danchik, Вы писали:

D>Появилась мысль что где-то у вас есть утечка графических ресурсов, и в какой-то момент это приводит к неработоспособности системы.

D>Например попробуйте эту тулзу http://www.nirsoft.net/utils/gdi_handles.html (нашел первое попавшееся)

Боюсь это не поможет, потому что при следующей (после черного прямоугольника) печати все печатается нормально
Re: Printer.Canvas.DrawRect
От: xp1icit  
Дата: 30.05.14 04:26
Оценка:
KB>TImage вместо картинки рисует черный прямоугольник. Причем не обязательно это должен быть канвас принтера, на форме тоже иногда бывает. Есть какие-нибудь идеи, как это побороть?

как-то напарывался на такое с одной картинкой в QRImage, выкрутился тупой заменой битмэпа на такой же с другой битностью цвета (ЕМНИП, битность уменьшал)
так что глубже не разбирался
Re[5]: Printer.Canvas.DrawRect
От: KaBoom Чехия  
Дата: 30.05.14 09:36
Оценка:
KB>
KB>   ACanvas.CopyRect(Rect(RLeft, RTop, RRight, RBottom), Picture.Bitmap.Canvas, Rect(0,0,Picture.Bitmap.Width, Picture.Bitmap.Height));
KB>


После этой процедуры попробовал проверить значения ACanvas.Pixels в той области, куда копировался битмап, а они все равны -1. Хотя картинка печатается нормально. Есть идеи почему так?
Re[6]: Printer.Canvas.DrawRect
От: Danchik Украина  
Дата: 30.05.14 13:36
Оценка:
Здравствуйте, KaBoom, Вы писали:

KB>>
KB>>   ACanvas.CopyRect(Rect(RLeft, RTop, RRight, RBottom), Picture.Bitmap.Canvas, Rect(0,0,Picture.Bitmap.Width, Picture.Bitmap.Height));
KB>>


KB>После этой процедуры попробовал проверить значения ACanvas.Pixels в той области, куда копировался битмап, а они все равны -1. Хотя картинка печатается нормально. Есть идеи почему так?


Может это и гадание на кофейной гуще. Но мне кажется что канва принтера, это что-то из разряда метафайла, не уверен что коректно у векторного представления просить пиксели.
Re[7]: Printer.Canvas.DrawRect
От: KaBoom Чехия  
Дата: 12.06.14 07:31
Оценка:
Здравствуйте, Danchik, Вы писали:

D>Здравствуйте, KaBoom, Вы писали:


KB>>>
KB>>>   ACanvas.CopyRect(Rect(RLeft, RTop, RRight, RBottom), Picture.Bitmap.Canvas, Rect(0,0,Picture.Bitmap.Width, Picture.Bitmap.Height));
KB>>>


KB>>После этой процедуры попробовал проверить значения ACanvas.Pixels в той области, куда копировался битмап, а они все равны -1. Хотя картинка печатается нормально. Есть идеи почему так?


D>Может это и гадание на кофейной гуще. Но мне кажется что канва принтера, это что-то из разряда метафайла, не уверен что коректно у векторного представления просить пиксели.



Удалось выяснить, что дело таки не в принтере и его канвас. Дело в загрузке TImage из TStream. Закономерность пока отловить не удалось, иногда 10000 загрузок подряд проходят нормально, а иногда подобные объекты начинают показывать черные квадраты через раз. Данные перепроверены тысячу раз, ошибок нигде никаких нет, но пофиксить это мне не удается. Изза этой долбаной проблемы я могу вылететь с работы, но идей никаких нету. Выручайте, братья.
Re[8]: Printer.Canvas.DrawRect
От: Softwarer http://softwarer.ru
Дата: 12.06.14 07:38
Оценка:
Здравствуйте, KaBoom, Вы писали:

KB> Дело в загрузке TImage из TStream. ... могу вылететь с работы,


Блин, ну несерьёзно.

1. Зачем грузить image 10000 раз? Грузите один раз и кэшируйте. Не верю я, что у вас на этикетках десятки тысяч картинок.

2. Если не удаётся найти причину, то блин уже писал — после загрузки проверяйте этот image, что в нём. Загрузился ли чёрный квадрат или нормальный рисунок. И тупо перегружайте, пока не загрузится, в конце-то концов.
Re[9]: Printer.Canvas.DrawRect
От: KaBoom Чехия  
Дата: 12.06.14 08:39
Оценка:
Здравствуйте, Softwarer, Вы писали:

S>Здравствуйте, KaBoom, Вы писали:


KB>> Дело в загрузке TImage из TStream. ... могу вылететь с работы,


S>Блин, ну несерьёзно.


S>1. Зачем грузить image 10000 раз? Грузите один раз и кэшируйте. Не верю я, что у вас на этикетках десятки тысяч картинок.


S>2. Если не удаётся найти причину, то блин уже писал — после загрузки проверяйте этот image, что в нём. Загрузился ли чёрный квадрат или нормальный рисунок. И тупо перегружайте, пока не загрузится, в конце-то концов.


Грузил я 10000 раз в качестве стресс-теста. Обычно на билете от одной до 5 картинок, редко больше. Кэшировать не выход — за день печати может случиться, что две одинаковые картинки не будут печататься, а печать идет тысячами. Картинка после загрузки, если произошел сбой, не полностью черная, а внизу битмапа несколько рядов разноцветных пикселей. Плюс я еще тормознул, и перепутал строки со столбцами пикселей, при проверке на одноцветность. В результате, в качестве костыля, решение сделано по Вашему варианту — проверяется верхняя половина картинки, если у всех пикселей цвет одинаковый — перезагрузка. Клиента это решение устраивает, но меня не очень. Лог показывает, что картинка может перегружаться до 5ти раз подряд, прежде чем загрузится нормально. Что за
Re[10]: Printer.Canvas.DrawRect
От: RainBoy  
Дата: 29.10.15 18:07
Оценка:
Canvas.Changed ?
... << RSDN@Home 2.2.0 alpha 5 rev. 0>>
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.