Модераторы: Snowy, Alexeis, MetalFan
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Карта города, Показ частей изображения по запросу 
:(
    Опции темы
PriZraK
  Дата 5.7.2008, 03:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 65
Регистрация: 22.10.2006

Репутация: нет
Всего: нет



Здравствуйте.

Бьюсь с решением проблемы реализации просмотра карты города. Изображение имеет огромнейшие размеры. Чтобы не хранить все изображение в памяти разрезал его на квадраты. Осталась проблема в написании кода, отображения части карты, а так же перемещение по ней с помощью мыши/скролбаров, с одновременной подгрузкой/выгрузкой нужных/ненужных участков карты.

Думаю работать необходимо через Canvas, только как именно...
Если что-то подобное уже было реализовано (не смог найти), укажите ссылкой.
PM MAIL ICQ Skype GTalk   Вверх
Данкинг
Дата 5.7.2008, 10:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Yersinia pestis
****


Профиль
Группа: Завсегдатай
Сообщений: 8302
Регистрация: 7.11.2006
Где: მოსკოვი

Репутация: нет
Всего: 130



Т.е. каждый квадрат - один файл? Ну и переименуй их в соответствии с условными координатами (1-1.jpg, 10-5.jpg) и грузи в TImage в нужном порядке!


--------------------
There's nothing left but silent epitaphs.
PM MAIL WWW   Вверх
Alexeis
Дата 5.7.2008, 10:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Амеба
Group Icon


Профиль
Группа: Админ
Сообщений: 11743
Регистрация: 12.10.2005
Где: Зеленоград

Репутация: 55
Всего: 459



PriZraK, Если картинка до 400 Мб, можно и не резать есть такая штука как Cachedbitmap (GDI+) или его самопальные аналоги. Суть в том, что изображение находиться на диске и отображается в память. Можно смело рисовать любые фрагменты, так как если бы картинка была загружена полностью. Винда сама будет подгружать в ОЗУ нужные куски и освобождать лишние.


--------------------
Vit вечная память.

Обсуждение действий администрации форума производятся только в этом форуме

гениальность идеи состоит в том, что ее невозможно придумать
PM ICQ Skype   Вверх
Kesh
Дата 5.7.2008, 12:28 (ссылка)    | (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Эксперт
Сообщений: 2488
Регистрация: 31.7.2002
Где: Германия, Saarbrü cken

Репутация: 1
Всего: 54



Когда-то давным давно заморачивался именно на эту тему... Использовал нарезанные PNG и компоненты DanJetX
Можете посмотреть вот тут... Правда времени нормально доделать так и не хватило, но кое-какие наработки были.



--------------------
user posted image
PM MAIL WWW ICQ Skype   Вверх
PriZraK
Дата 5.7.2008, 16:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 65
Регистрация: 22.10.2006

Репутация: нет
Всего: нет



Спасибо большое за подсказки, попробую реализовывать.
PM MAIL ICQ Skype GTalk   Вверх
PriZraK
Дата 10.7.2008, 17:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 65
Регистрация: 22.10.2006

Репутация: нет
Всего: нет



Цитата(Alexeis @ 5.7.2008,  10:53)
PriZraK, Если картинка до 400 Мб, можно и не резать есть такая штука как Cachedbitmap (GDI+) или его самопальные аналоги. Суть в том, что изображение находиться на диске и отображается в память. Можно смело рисовать любые фрагменты, так как если бы картинка была загружена полностью. Винда сама будет подгружать в ОЗУ нужные куски и освобождать лишние.

Немогу осилить Cachedbitmap (GDI+), можно попросить пример кода?

Нашёл этот код, уже что-то, но все же изображение хранится полностью в памяти.
Код

function MyGetMem(Size: DWORD): Pointer;
 begin
   Result := Pointer(GlobalAlloc(GPTR, Size));
 end;

 procedure MyFreeMem(p: Pointer);
 begin
   if p = nil then Exit;
   GlobalFree(THandle(p));
 end;

 { This code will fill a bitmap by stretching an image coming from a big bitmap on disk. 

  FileName.- Name of the uncompressed bitmap to read 
  DestBitmap.- Target bitmap  where the bitmap on disk will be resampled. 
  BufferSize.- The size of a memory buffer used for reading scanlines from the physical bitmap on disk. 
    This value will decide how many scanlines can be read from disk at the same time, with always a 
    minimum value of 2 scanlines. 

  Will return false on error. 
}
 function GetDIBInBands(const FileName: string;
   DestBitmap: TBitmap; BufferSize: Integer;
   out TotalBitmapWidth, TotalBitmapHeight: Integer): Boolean;
 var
   FileSize: integer;    // calculated file size 
  ImageSize: integer;    // calculated image size 
  dest_MaxScans: integer;  // number of scanline from source bitmap 
  dsty_top: Integer;    // used to calculate number of passes 
  NumPasses: integer;    // number of passed needed 
  dest_Residual: integer;  // number of scanlines on last band 
  Stream: TStream;    // stream used for opening the bitmap 
  bmf: TBITMAPFILEHEADER;  // the bitmap header 
  lpBitmapInfo: PBITMAPINFO;  // bitmap info record 
  BitmapHeaderSize: integer;  // size of header of bitmap 
  SourceIsTopDown: Boolean;  // is reversed bitmap ? 
  SourceBytesPerScanLine: integer;  // number of bytes per scanline 
  SourceLastScanLine: Extended;     // last scanline processes 
  SourceBandHeight: Extended;       // 
  BitmapInfo: PBITMAPINFO;
   img_start: integer;
   img_end: integer;
   img_numscans: integer;
   OffsetInFile: integer;
   OldHeight: Integer;
   bits: Pointer;
   CurrentTop: Integer;
   CurrentBottom: Integer;
 begin
   Result := False;

   // open the big bitmap 
  Stream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);

   // total size of bitmap 
  FileSize := Stream.Size;
   // read the header 
  Stream.ReadBuffer(bmf, SizeOf(TBITMAPFILEHEADER));
   // calculate header size 
  BitmapHeaderSize := bmf.bfOffBits - SizeOf(TBITMAPFILEHEADER);
   // calculate size of bitmap bits 
  ImageSize := FileSize - Integer(bmf.bfOffBits);
   // check for valid bitmap and exit if not 
  if ((bmf.bfType <> $4D42) or
     (Integer(bmf.bfOffBits) < 1) or
     (FileSize < 1) or (BitmapHeaderSize < 1) or (ImageSize < 1) or
     (FileSize < (SizeOf(TBITMAPFILEHEADER) + BitmapHeaderSize + ImageSize))) then
   begin
     Stream.Free;
     Exit;
   end;
   lpBitmapInfo := MyGetMem(BitmapHeaderSize);
   try
     Stream.ReadBuffer(lpBitmapInfo^, BitmapHeaderSize);
     // check for uncompressed bitmap 
    if ((lpBitmapInfo^.bmiHeader.biCompression = BI_RLE4) or
       (lpBitmapInfo^.bmiHeader.biCompression = BI_RLE8)) then
     begin
       Exit;
     end;

     // bitmap dimensions 
    TotalBitmapWidth  := lpBitmapInfo^.bmiHeader.biWidth;
     TotalBitmapHeight := abs(lpBitmapInfo^.bmiHeader.biHeight);

     // is reversed order ? 
    SourceIsTopDown := (lpBitmapInfo^.bmiHeader.biHeight < 0);

     // calculate number of bytes used per scanline 
    SourceBytesPerScanLine := ((((lpBitmapInfo^.bmiHeader.biWidth *
       lpBitmapInfo^.bmiHeader.biBitCount) + 31) and not 31) div 8);

     // adjust buffer size 
    if BufferSize < Abs(SourceBytesPerScanLine) then
       BufferSize := Abs(SourceBytesPerScanLine);

     // calculate number of scanlines for every pass on the destination bitmap 
    dest_MaxScans := round(BufferSize / abs(SourceBytesPerScanLine));
     dest_MaxScans := round(dest_MaxScans * (DestBitmap.Height / TotalBitmapHeight));

     if dest_MaxScans < 2 then
       dest_MaxScans := 2;         // at least two scan lines 

    // is not big enough ? 
    if dest_MaxScans > TotalBitmapHeight then
       dest_MaxScans := TotalBitmapHeight;

     { count the number of passes needed to fill the destination bitmap }
     dsty_top  := 0;
     NumPasses := 0;
     while (dsty_Top + dest_MaxScans) <= DestBitmap.Height do
     begin
       Inc(NumPasses);
       Inc(dsty_top, dest_MaxScans);
     end;
     if NumPasses = 0 then Exit;

     // calculate scanlines on last pass 
    dest_Residual := DestBitmap.Height mod dest_MaxScans;

     // now calculate how many scanlines in source bitmap needed for every band on the destination bitmap 
    SourceBandHeight := (TotalBitmapHeight * (1 - (dest_Residual / DestBitmap.Height))) /
       NumPasses;

     // initialize first band 
    CurrentTop    := 0;
     CurrentBottom := dest_MaxScans;

     // a floating point used in order to not loose last scanline precision on source bitmap 
    // because every band on target could be a fraction (not integral) on the source bitmap 
    SourceLastScanLine := 0.0;

     while CurrentTop < DestBitmap.Height do
     begin
       // scanline start of band in source bitmap 
      img_start          := Round(SourceLastScanLine);
       SourceLastScanLine := SourceLastScanLine + SourceBandHeight;
       // scanline finish of band in source bitmap 
      img_end := Round(SourceLastScanLine);
       if img_end > TotalBitmapHeight - 1 then
         img_end := TotalBitmapHeight - 1;
       img_numscans := img_end - img_start;
       if img_numscans < 1 then Break;
       OldHeight := lpBitmapInfo^.bmiHeader.biHeight;
       if SourceIsTopDown then
         lpBitmapInfo^.bmiHeader.biHeight := -img_numscans
       else
         lpBitmapInfo^.bmiHeader.biHeight := img_numscans;

       // memory used to read only the current band 
      bits := MyGetMem(Abs(SourceBytesPerScanLine) * img_numscans);

       try
         // calculate offset of band on disk 
        OffsetInFile := TotalBitmapHeight - (img_start + img_numscans);
         Stream.Seek(Integer(bmf.bfOffBits) + (OffsetInFile * abs(SourceBytesPerScanLine)),
           soFromBeginning);
         Stream.ReadBuffer(bits^, abs(SourceBytesPerScanLine) * img_numscans);

         SetStretchBltMode(DestBitmap.Canvas.Handle, COLORONCOLOR);
         // now stretch the band readed to the destination bitmap 
        StretchDIBits(DestBitmap.Canvas.Handle,
           0,
           CurrentTop,
           DestBitmap.Width,
           Abs(CurrentBottom - CurrentTop),
           0,
           0,
           TotalBitmapWidth,
           img_numscans,
           Bits,
           lpBitmapInfo^,
           DIB_RGB_COLORS, SRCCOPY);
       finally
         MyFreeMem(bits);
         lpBitmapInfo^.bmiHeader.biHeight := OldHeight;
       end;

       CurrentTop    := CurrentBottom;
       CurrentBottom := CurrentTop + dest_MaxScans;
       if CurrentBottom > DestBitmap.Height then
         CurrentBottom := DestBitmap.Height;
     end;
   finally
     Stream.Free;
     MyFreeMem(lpBitmapInfo);
   end;
   Result := True;
 end;

 // example of usage 
procedure TForm1.Button1Click(Sender: TObject);
 var
   bmw, bmh: Integer;
   Bitmap: TBitmap;
 begin
   Bitmap := TBitmap.Create;
   with TOpenDialog.Create(nil) do
     try
       DefaultExt := 'BMP';
       Filter := 'Bitmaps (*.bmp)|*.bmp';
       Title := 'Define bitmap to display';
       if not Execute then Exit;
       { define the size of the required bitmap }
       Bitmap.Width       := Self.ClientWidth;
       Bitmap.Height      := Self.ClientHeight;
       Bitmap.PixelFormat := pf24Bit;
       Screen.Cursor      := crHourglass;
       // use 100 KB of buffer 
      if not GetDIBInBands(FileName, Bitmap, 100 * 1024, bmw, bmh) then Exit;
       // original bitmap width = bmw 
      // original bitmap height = bmh 
      Self.Canvas.Draw(0,0,Bitmap);
     finally
       Free;
       Bitmap.Free;
       Screen.Cursor := crDefault;
     end;
 end;


Это сообщение отредактировал(а) PriZraK - 10.7.2008, 23:51
PM MAIL ICQ Skype GTalk   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Delphi: Звук, графика и видео"
Girder
Snowy
Alexeis

Запрещено:

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делится вскрытыми компонентами

  • Литературу по Дельфи обсуждаем здесь
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь
  • 90% ответов на свои вопросы можно найти в DRKB (Delphi Russian Knowledge Base) - крупнейшем в рунете сборнике материалов по Дельфи
  • По вопросам разработки игр стоит заглянуть сюда

FAQ раздела лежит здесь!


Если Вам помогли и атмосфера форума Вам понравилась, то заходите к нам чаще! С уважением, Girder, Snowy.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Delphi: Звук, графика и видео | Следующая тема »


 




[ Время генерации скрипта: 0.0558 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.