Можно ли считывать часть большого BMP файла не считывая весь
От: miklek  
Дата: 14.04.09 07:14
Оценка:
Считывать весь файл нельзя, т.к. оперативная память забивается сотнями MB, а с программой работают несколько пользователей в терминале, сервак не выдерживает. Надо либо научится считывать часть большого BMP файла, либо научить программу не кушать оперативку при отображении всего файла, что врядли возможно.
Считываю файл стандартной командой:

Bitmap:=TBitmap.Create();
Bitmap.LoadFromFile(<Путь к файлу>);
или
Image:=TImage.Create(ScrollBox);
Image.Picture.LoadFromFile(<Путь к файлу>);
Re: Можно ли считывать часть большого BMP файла не считывая
От: MegaVoltik  
Дата: 14.04.09 07:48
Оценка:
M>Считывать весь файл нельзя, т.к. оперативная память забивается сотнями MB, а с программой работают несколько пользователей в терминале, сервак не выдерживает. Надо либо научится считывать часть большого BMP файла, либо научить программу не кушать оперативку при отображении всего файла, что врядли возможно.

Если стоит задача чтобы много пользователей работало с одним большим файлом то проще держать фал в памяти но одну копию а пользователям раздавать только нужные им куски.

Если же файлов много и пользователей много то напиши свою читалку DVG файлов формат совершенно не сложный. И за заголовком данные лежать просто строчками. Можно запросто с каждой строчки читать только тот кусочек который нужен и в результате иметь маленький кусочек.
Чем больше нас, тем меньше их...
Re: Можно ли считывать часть большого BMP файла не считывая
От: MikelSV http://www.centerix.ru
Дата: 14.04.09 12:05
Оценка:
Здравствуйте, miklek, Вы писали:

...


Как-то мне понадобилось отображать картинку на КПК, но там были проблемы с раскодированием, в результате чего был создан свой формат.

Думаю и здесь такой формат пойдет отлично. Это в принципе уже распакованное изображени.
если коротко, файл: шапка: ширина, высота и кажется все. и данные по 3байта(или 4) на пиксель. теперь координаты известны. остается считать и передать клиенту. и скорость отличная. придется пожертвовать местом для новых файлов, но эт в принципе не страшно.

Естественно сначала надо переделать из обычного в этот.

(кажется я даже дал им расширение .mim: my image ^_^)
Римское правило. Тот, кто говорит, что Это не может быть сделано, никогда не должен мешать тому, кто Это делает.
Осень, ну вы поняли.
Зачем еще один код? А человек?
Re[2]: Можно ли считывать часть большого BMP файла не считыв
От: MegaVoltik  
Дата: 14.04.09 12:22
Оценка:
MSV>в результате чего был создан свой формат.

И чем он принципиально отличается от BMP?
Чем больше нас, тем меньше их...
Re[3]: Можно ли считывать часть большого BMP файла не считыв
От: MikelSV http://www.centerix.ru
Дата: 15.04.09 20:33
Оценка:
Здравствуйте, MegaVoltik, Вы писали:

MSV>>в результате чего был создан свой формат.


MV>И чем он принципиально отличается от BMP?


Фик знает. может почти ничем. я jpeg перекодировал. зато потом не имел проблем. если сможешь разобраться, где находятся данные в bmp, вперед :]
Римское правило. Тот, кто говорит, что Это не может быть сделано, никогда не должен мешать тому, кто Это делает.
Осень, ну вы поняли.
Зачем еще один код? А человек?
Re: Можно ли считывать часть большого BMP файла не считывая
От: int64 Россия  
Дата: 16.04.09 06:56
Оценка:
Здравствуйте, miklek, Вы писали:

http://www.delphi-7.net/Glava10/Index17.htm
Re[2]: Можно ли считывать часть большого BMP файла не считыв
От: miklek  
Дата: 16.04.09 08:35
Оценка:
Здравствуйте, int64, Вы писали:

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

I>http://www.delphi-7.net/Glava10/Index17.htm

Спасибо за ответ. С этой статьей я познакомился еще до того как задал вопрос, но к сожалению автор статьи очень не корректно скопировал в нее код примера или набирал с опечатками. Пример просто ругается при компиляции почти на каждой строке (не корректные типы и т.п. и т.д.), описание куцее, разобраться проблематично. Мне бы схемку аль чертеж... Помогите, пожалуйста.
Re[3]: Можно ли считывать часть большого BMP файла не считыв
От: int64 Россия  
Дата: 16.04.09 10:10
Оценка:
Здравствуйте, miklek, Вы писали:

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


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

I>>http://www.delphi-7.net/Glava10/Index17.htm

M>Спасибо за ответ. С этой статьей я познакомился еще до того как задал вопрос, но к сожалению автор статьи очень не корректно скопировал в нее код примера или набирал с опечатками. Пример просто ругается при компиляции почти на каждой строке (не корректные типы и т.п. и т.д.), описание куцее, разобраться проблематично. Мне бы схемку аль чертеж... Помогите, пожалуйста.


Да, потому что это скан. В результате нек символы стали русскими, 1 стала l, итд.
Полностью работающий этот код я видел на дискетке к какой-то книге по Delphi 4 в 2001г. Сам от туда его брал.
Авторы Марков и грузин.

Рекомендую своеручно исправить код, объявить пользовательские типы и переменные. Все заработает.
Re[3]: Можно ли считывать часть большого BMP файла не считыв
От: Aniskin  
Дата: 16.04.09 15:14
Оценка:
Здравствуйте, miklek, Вы писали:

M>Мне бы схемку аль чертеж... Помогите, пожалуйста.


Может быть как-нибудь так:

unit decMappingBitmap;

{.$DEFINE EASY}

interface

uses Windows {$IFNDEF EASY}, Classes, Graphics, SysUtils {$ENDIF};

type
  TdecBitmapInfo = packed record
    bmiHeader: TBitmapInfoHeader;
    bmiColors: array[0..255] of TRGBQuad;
  end;

  TdecMappingBitmapImage = class {$IFNDEF EASY}(TSharedImage){$ENDIF}
  public
    constructor Create(const AFilename: string);
    destructor Destroy; override;
    procedure Draw(ADC: HDC; const ARect: TRect; ACopyMode: Integer = SRCCOPY);
  protected
    {$IFNDEF EASY}
    procedure FreeHandle; override;
    {$ENDIF}
  private
    FFileHandle: THandle;
    FMappingHandle: THandle;
    FData: Pointer;
    FFileHeader : TBitmapFileHeader;
    FInfo: TdecBitmapInfo;
    FBits: Pointer;
    function GetEmpty: Boolean;
    function GetHeight: Integer;
    function GetPalette: HPALETTE;
    function GetTransparent: Boolean;
    function GetWidth: Integer;
  public
    property Empty: Boolean read GetEmpty;
    property Height: Integer read GetHeight;
    property Palette: HPALETTE read GetPalette;
    property Transparent: Boolean read GetTransparent;
    property Width: Integer read GetWidth;
  end;

  {$IFNDEF EASY}
  TdecMappingBitmap = class(TGraphic)
  public
    destructor Destroy; override;
    procedure Assign(Source: TPersistent); override;
    procedure LoadFromFile(const AFilename: string); override;
    procedure SaveToFile(const AFilename: string); override;
    procedure LoadFromStream(AStream: TStream); override;
    procedure SaveToStream(AStream: TStream); override;
    procedure LoadFromClipboardFormat(AFormat: Word; AData: THandle;
      APalette: HPALETTE); override;
    procedure SaveToClipboardFormat(var AFormat: Word; var AData: THandle;
      var APalette: HPALETTE); override;
  protected
    procedure Draw(ACanvas: TCanvas; const ARect: TRect); override;
    function Equals(AGraphic: TGraphic): Boolean; override;
    function GetEmpty: Boolean; override;
    function GetHeight: Integer; override;
    function GetPalette: HPALETTE; override;
    function GetTransparent: Boolean; override;
    function GetWidth: Integer; override;
    procedure ReadData(Stream: TStream); override;
    procedure SetHeight(Value: Integer); override;
    procedure SetPalette(Value: HPALETTE); override;
    procedure SetTransparent(Value: Boolean); override;
    procedure SetWidth(Value: Integer); override;
    procedure WriteData(Stream: TStream); override;
  private
    FImage: TdecMappingBitmapImage;
  end;
  {$ENDIF}

implementation

{$IFNDEF EASY}
type
  EdecMappingBitmapException = class(Exception);

procedure InvalidOperaion;
begin
  raise EdecMappingBitmapException.Create('Invalid operation');
end;
{$ENDIF}

//******************************************************************************
// TdecMappingBitmapImage
//******************************************************************************

constructor TdecMappingBitmapImage.Create(const AFilename: string);
var Size: Integer;
    Temp: Pointer;
begin
  inherited Create;
  FFileHandle := CreateFile(PChar(AFileName), GENERIC_READ or GENERIC_WRITE,
    FILE_SHARE_READ, nil, OPEN_EXISTING, 0, 0);
  if FFileHandle = INVALID_HANDLE_VALUE then
    begin
      FFileHandle := 0;
      {$IFNDEF EASY}
      RaiseLastOSError;
      {$ELSE}
      exit;
      {$ENDIF}
    end;
  FMappingHandle := CreateFileMapping(FFileHandle, nil, PAGE_READONLY, 0, 0, nil);
  if FMappingHandle = 0 then
    begin
      {$IFNDEF EASY}
      RaiseLastOSError;
      {$ELSE}
      exit;
      {$ENDIF}
    end;
  FData := MapViewOfFile(FMappingHandle, FILE_MAP_READ, 0, 0, 0);
  if FData = nil then
    begin
      {$IFNDEF EASY}
      RaiseLastOSError;
      {$ELSE}
      exit;
      {$ENDIF}
    end;
  if PBitmapFileHeader(FData).bfType <> $4D42 then
    begin
      {$IFNDEF EASY}
      EdecMappingBitmapException.Create('Invalid bitmap');
      {$ELSE}
      UnMapViewOfFile(FData);
      FData := nil;
      exit;
      {$ENDIF}
    end;
  FFileHeader := PBitmapFileHeader(FData)^;
  FBits :=Pointer(DWORD(FData) + FFileHeader.bfOffBits);
  Temp := Pointer(Integer(FData) + SizeOf(FFileHeader));
  Size := PBitmapInfoHeader(Temp)^.biSize;
  if Size > SizeOf(FInfo.bmiHeader) then Size := SizeOf(FInfo.bmiHeader);
  ZeroMemory(@FInfo, SizeOf(FInfo));
  CopyMemory(@FInfo.bmiHeader, Temp, Size);
  if FInfo.bmiHeader.biBitCount <= 8 then
    begin
      Temp := Pointer(DWORD(Temp) + PBitmapInfoHeader(Temp)^.biSize);
      CopyMemory(@FInfo.bmiColors[0], Temp, 1 shl FInfo.bmiHeader.biBitCount * SizeOf(FInfo.bmiColors[0]));
    end;
end;

destructor TdecMappingBitmapImage.Destroy;
begin
  if FData <> nil then UnMapViewOfFile(FData);
  if FMappingHandle <> 0 then CloseHandle(FMappingHandle);
  if FFileHandle <> 0 then CloseHandle(FFileHandle);
  inherited Destroy;
end;

procedure TdecMappingBitmapImage.Draw(ADC: HDC; const ARect: TRect; ACopyMode: Integer = SRCCOPY);
var W, H: Integer;
    Save: Integer;
begin
  if FData = nil then exit;
  with ARect do
    begin
      W := Right - Left;
      H := Bottom - Top;
    end;
  if (W = 0) or (H = 0) then exit;  
  if (W = Width) and (H = Height) and (ACopyMode = SRCCOPY) then
    SetDIBitsToDevice(ADC, ARect.Left, ARect.Top, W, H, 0, 0, 0, Height, FBits, PBitmapInfo(@FInfo)^, DIB_RGB_COLORS)
  else
    begin
      Save := SetStretchBltMode(ADC, STRETCH_DELETESCANS);
      StretchDIBits(ADC, ARect.Left, ARect.Top, W, H, 0, 0, Width, Height, FBits, PBitmapInfo(@FInfo)^, DIB_RGB_COLORS, ACopyMode);
      SetStretchBltMode(ADC, Save);
    end;
end;

{$IFNDEF EASY}
procedure TdecMappingBitmapImage.FreeHandle;
begin

end;
{$ENDIF}

function TdecMappingBitmapImage.GetEmpty: Boolean;
begin
  Result := FData = nil;
end;

function TdecMappingBitmapImage.GetHeight: Integer;
begin
  if Empty then Result := 0
           else Result := Abs(FInfo.bmiHeader.biHeight);
end;

function TdecMappingBitmapImage.GetPalette: HPALETTE;
begin
  Result := 0; // TO DO
end;

function TdecMappingBitmapImage.GetTransparent: Boolean;
begin
  Result := False; // TO DO
end;

function TdecMappingBitmapImage.GetWidth: Integer;
begin
  if Empty then Result := 0
           else Result := FInfo.bmiHeader.biWidth;
end;

{$IFNDEF EASY}
//******************************************************************************
// TdecMappingBitmap
//******************************************************************************

destructor TdecMappingBitmap.Destroy;
begin
  if FImage <> nil then FImage.Release;
  inherited Destroy;
end;

procedure TdecMappingBitmap.Assign(Source: TPersistent);
begin
  if (Source = nil) or (Source is TdecMappingBitmap) then
    begin
      FImage.Release;
      if Source <> nil then
        begin
          TdecMappingBitmap(Source).FImage.Reference;
          FImage := TdecMappingBitmap(Source).FImage;
        end;
      Changed(Self);
    end
  else
    inherited Assign(Source);
end;

procedure TdecMappingBitmap.LoadFromFile(const AFilename: string);
begin
  if FImage <> nil then FImage.Release;
  FImage := TdecMappingBitmapImage.Create(AFilename);
  FImage.Reference;
  Changed(Self);
end;

procedure TdecMappingBitmap.SaveToFile(const AFilename: string);
begin
  InvalidOperaion;
end;

procedure TdecMappingBitmap.LoadFromStream(AStream: TStream);
begin
  InvalidOperaion;
end;

procedure TdecMappingBitmap.SaveToStream(AStream: TStream);
begin
  InvalidOperaion;
end;

procedure TdecMappingBitmap.LoadFromClipboardFormat(AFormat: Word; AData: THandle;
  APalette: HPALETTE);
begin
  InvalidOperaion;
end;

procedure TdecMappingBitmap.SaveToClipboardFormat(var AFormat: Word; var AData: THandle;
  var APalette: HPALETTE);
begin
  InvalidOperaion;
end;

procedure TdecMappingBitmap.Draw(ACanvas: TCanvas; const ARect: TRect);
begin
  if FImage <> nil then
    FImage.Draw(ACanvas.Handle, ARect, ACanvas.CopyMode);
end;

function TdecMappingBitmap.Equals(AGraphic: TGraphic): Boolean;
begin
  Result := (AGraphic <> nil) and (AGraphic is TdecMappingBitmap) and (TdecMappingBitmap(AGraphic).FImage = FImage);
end;

function TdecMappingBitmap.GetEmpty: Boolean;
begin
  Result := (FImage = nil) or (FImage.Empty);
end;

function TdecMappingBitmap.GetHeight: Integer;
begin
  if Empty then Result := 0
           else Result := FImage.Height;
end;

function TdecMappingBitmap.GetPalette: HPALETTE;
begin
  if Empty then Result := 0
           else Result := FImage.Palette;
end;

function TdecMappingBitmap.GetTransparent: Boolean;
begin
  if Empty then Result := False
           else Result := FImage.Transparent;
end;

function TdecMappingBitmap.GetWidth: Integer;
begin
  if Empty then Result := 0
           else Result := FImage.Width;
end;

procedure TdecMappingBitmap.ReadData(Stream: TStream);
begin
  InvalidOperaion;
end;

procedure TdecMappingBitmap.SetHeight(Value: Integer);
begin
  InvalidOperaion;
end;

procedure TdecMappingBitmap.SetPalette(Value: HPALETTE);
begin
  InvalidOperaion;
end;

procedure TdecMappingBitmap.SetTransparent(Value: Boolean);
begin
  // Ignore
end;

procedure TdecMappingBitmap.SetWidth(Value: Integer);
begin
  InvalidOperaion;
end;

procedure TdecMappingBitmap.WriteData(Stream: TStream);
begin
  InvalidOperaion;
end;
{$ENDIF}

end.
Re[4]: Можно ли считывать часть большого BMP файла не считыв
От: miklek  
Дата: 17.04.09 05:29
Оценка:
На www.delphimaster.ru предложили решение загрузки большого файла BMP без большого расходования ОЗУ.
Файл в 300 MB кушает 3 MB оперативки. Пример прикреплен http://files.rsdn.ru/80761/BMP%20Big.rar
Вопрос решен.
Re[5]: Можно ли считывать часть большого BMP файла не считыв
От: miklek  
Дата: 17.04.09 05:31
Оценка:
Не понял, почему файл не прикрепился?
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.