1

画像をデータベースに保存するプログラムを作ろうとしています。私はネット上のいくつかの情報をまとめて、動作すると思われるコードを書きましたが、いずれかの側 (保存と読み込み) で完全にユニークな方法で失敗します。

これが私のコードです。何が間違っているのか教えていただけますか?

データベースからロードすると、メモリ アドレス アクセス違反エラーが発生します。

    procedure TfrmMain.btnAddPickT4Click(Sender: TObject);
    var
      S : TMemoryStream;
      ikode : integer;
    begin

      if cbxDeelnemerT4.ItemIndex < 0 then
      begin
        MessageDlg('Kies asseblief ''n deelnemer!',mtInformation,[mbOK],1);
        Exit;
      end;

      if OpenPictureDialog1.Execute then
        if FileExists(OpenPictureDialog1.FileName) then
          Image1.Picture.LoadFromFile(OpenPictureDialog1.FileName)
        else
          MessageDlg('Die lêer bestaan nie!',mtError,[mbOK],1);

      ikode := cbxDeelnemerT4.ItemIndex + 1;
      S := TMemoryStream.Create;
      ADOQuery1.Close;
      ADOQuery1.SQL.Text := 'SELECT * FROM DEELNEMERS WHERE Kode = '+inttostr(ikode);
      ADOQuery1.Open;
      try
        Image1.Picture.Graphic.SaveToStream(S);
        S.Position := 1;
        ADOQuery1.Insert;
        TBLobfield(ADOQuery1.FieldByName('Foto')).LoadFromStream(S);
      finally
        S.Free;
      end;


    end;

データベースに保存しています。このコード自体はエラーにはなりませんが、画像をデータベースに保存しません:

procedure TfrmMain.btnOpenProfileT4Click(Sender: TObject);
var
  S : TMemoryStream;
  ikode : integer;
begin

    ikode := cbxDeelnemerT4.ItemIndex + 1;
  S := TMemoryStream.Create;
  ADOQuery1.Close;
  ADOQuery1.SQL.Text := 'SELECT * FROM DEELNEMERS WHERE Kode = '+inttostr(ikode);
  ADOQuery1.Open;
  try
    TBlobField(ADOQuery1.FieldByName('Foto')).SaveToStream(S);
    S.Position := 0;
    Image1.Picture.Graphic.LoadFromStream(S);

  finally
   s.Free;
  end;

end;
4

1 に答える 1

4

呼び出していますが、事前に有効な派生オブジェクトでプロパティをTGraphic.LoadFromStream()初期化していないため、プロパティがクラッシュする可能性があります。TPicture.GraphicTGraphicnil

また、 を に保存するTPicture.Graphic場合TMemoryStream、DB に保存するときにグラフィックの最初のバイトをスキップしています。すべてのバイトが重要なので、スキップしないでください。

画像が具体的には JPEG であり、他に何もないと仮定すると (保存コードはファイルの種類を制限していません)、代わりにこれを試してください:

procedure TfrmMain.btnAddPickT4Click(Sender: TObject);
var
  S : TMemoryStream;
  ikode : integer;
begin
  if cbxDeelnemerT4.ItemIndex < 0 then
  begin
    MessageDlg('Kies asseblief ''n deelnemer!',mtInformation,[mbOK],1);
    Exit;
  end;

  if not OpenPictureDialog1.Execute then
    Exit;

  Image1.Picture.LoadFromFile(OpenPictureDialog1.FileName);
  if not (Image1.Picture.Graphic is TJpegImage) then
    raise Exception.Create('Sorry, only JPG images can be saved in the DB');

  ikode := cbxDeelnemerT4.ItemIndex + 1;
  S := TMemoryStream.Create;
  try
    Image1.Picture.Graphic.SaveToStream(S);
    S.Position := 0;

    ADOQuery1.Close;
    ADOQuery1.SQL.Text := 'SELECT * FROM DEELNEMERS WHERE Kode = '+IntToStr(ikode);
    ADOQuery1.Open;
    ADOQuery1.Insert;
    try
      TBlobField(ADOQuery1.FieldByName('Foto')).LoadFromStream(S);
      ADOQuery1.Post;
    except
      ADOQuery1.Cancel;
      raise;
    end;
  finally
    S.Free;
  end;
end;

uses
  ..., Jpeg;

procedure TfrmMain.btnOpenProfileT4Click(Sender: TObject);
var
  S : TMemoryStream;
  ikode : integer;
  Jpg: TJPEGImage;
begin
  ikode := cbxDeelnemerT4.ItemIndex + 1;

  ADOQuery1.Close;
  ADOQuery1.SQL.Text := 'SELECT * FROM DEELNEMERS WHERE Kode = ' + IntToStr(ikode);
  ADOQuery1.Open;

  S := TMemoryStream.Create;
  try
    TBlobField(ADOQuery1.FieldByName('Foto')).SaveToStream(S);
    S.Position := 0;

    Jpg := TJPEGImage.Create;
    try
      Jpg.LoadFromStream(S);
      Image1.Picture.Assign(Jpg);
    finally
      Jpg.Free;
    end;
  finally
    S.Free;
  end;    
end;

ただし、画像が JPEG 以外の形式である可能性がある場合は、画像タイプを DB に保存して、それを読み戻して正しいTGraphicクラス タイプ ( TBitmapTJpegImageTGifImageTPNGImageなど) をインスタンス化し、必要に応じて処理できるようにする必要があります。例えば:

procedure TfrmMain.btnAddPickT4Click(Sender: TObject);
var
  S : TMemoryStream;
  ikode : integer;
begin
  if cbxDeelnemerT4.ItemIndex < 0 then
  begin
    MessageDlg('Kies asseblief ''n deelnemer!',mtInformation,[mbOK],1);
    Exit;
  end;

  if not OpenPictureDialog1.Execute then
    Exit;

  Image1.Picture.LoadFromFile(OpenPictureDialog1.FileName);

  ikode := cbxDeelnemerT4.ItemIndex + 1;
  S := TMemoryStream.Create;
  try
    Image1.Picture.Graphic.SaveToStream(S);
    S.Position := 0;

    ADOQuery1.Close;
    ADOQuery1.SQL.Text := 'SELECT * FROM DEELNEMERS WHERE Kode = '+IntToStr(ikode);
    ADOQuery1.Open;
    ADOQuery1.Insert;
    try
      // this is just an example, there are other ways to do this
      if Image1.Picture.Graphic is TJPEGImage then
        ADOQuery1.FieldByName('FotoType').AsString := 'jpg'
      else if Image1.Picture.Graphic is TPNGImage then
        ADOQuery1.FieldByName('FotoType').AsString := 'png'
      else if Image1.Picture.Graphic is TGIFImage then
        ADOQuery1.FieldByName('FotoType').AsString := 'gif'
      else if Image1.Picture.Graphic is TBitmap then
        ADOQuery1.FieldByName('FotoType').AsString := 'bmp'
      else
        raise Exception.Create('Cannot save unsupported image type to DB');

      TBlobField(ADOQuery1.FieldByName('Foto')).LoadFromStream(S);

      ADOQuery1.Post;
    except
      ADOQuery1.Cancel;
      raise;
    end;
  finally
    S.Free;
  end;
end;

uses
  ..., Jpeg, GifImg, PngImg;

procedure TfrmMain.btnOpenProfileT4Click(Sender: TObject);
var
  S : TMemoryStream;
  ikode : integer;
  Graphic: TGraphic;
  GraphicType: String;
begin
  ikode := cbxDeelnemerT4.ItemIndex + 1;

  ADOQuery1.Close;
  ADOQuery1.SQL.Text := 'SELECT * FROM DEELNEMERS WHERE Kode = ' + IntToStr(ikode);
  ADOQuery1.Open;

  S := TMemoryStream.Create;
  try
    TBlobField(ADOQuery1.FieldByName('Foto')).SaveToStream(S);
    S.Position := 0;

    GraphicType := ADOQuery1.FieldByName('FotoType').AsString;

    if GraphicType = 'jpg' then
      Graphic := TJPEGImage.Create
      ADOQuery1.FieldByName('FotoType').AsString := 'jpg'
    else if GraphicType = 'png' then
      Graphic := TPNGImage.Create
    else if GraphicType = 'gif' then
      Graphic := TGifImage.Create
    else if GraphicType = 'bmp' then
      Graphic := TBitmap.Create
    else
      raise Exception.Create('Cannot load unsupported image type from DB');

    try
      Graphic.LoadFromStream(S);
      Image1.Picture.Assign(Graphic);
    finally
      Graphic.Free;
    end;
  finally
    S.Free;
  end;    
end;

TBlobFieldそうは言っても、直接アクセスするべきではありません。TDataSet.CreateBlobStream()代わりにメソッドを使用して、ADO が ADO​​ blob データへのアクセス用に最適化されたオブジェクトを提供できるようにしますTStream

procedure TfrmMain.btnAddPickT4Click(Sender: TObject);
var
  S : TStream;
  ikode : integer;
begin
  if cbxDeelnemerT4.ItemIndex < 0 then
  begin
    MessageDlg('Kies asseblief ''n deelnemer!',mtInformation,[mbOK],1);
    Exit;
  end;

  if not OpenPictureDialog1.Execute then
    Exit;

  Image1.Picture.LoadFromFile(OpenPictureDialog1.FileName);

  ikode := cbxDeelnemerT4.ItemIndex + 1;

  ADOQuery1.Close;
  ADOQuery1.SQL.Text := 'SELECT * FROM DEELNEMERS WHERE Kode = '+IntToStr(ikode);
  ADOQuery1.Open;
  ADOQuery1.Insert;
  try
    ...

    S := ADOQuery1.CreateBlobStream(ADOQuery1.FieldByName('Foto'), bmWrite);
    try
      Image1.Picture.Graphic.SaveToStream(S);
    finally
      S.Free;
    end;

    ADOQuery1.Post;
  except
    ADOQuery1.Cancel;
    raise;
  end;
end;

procedure TfrmMain.btnOpenProfileT4Click(Sender: TObject);
var
  S : TStream;
  ikode : integer;
  Graphic: TGraphic;
begin
  ikode := cbxDeelnemerT4.ItemIndex + 1;

  ADOQuery1.Close;
  ADOQuery1.SQL.Text := 'SELECT * FROM DEELNEMERS WHERE Kode = ' + IntToStr(ikode);
  ADOQuery1.Open;

  ...

  Graphic := ...;
  try
    S := ADOQuery1.CreateBlobStream(ADOQuery1.FieldByName('Foto'), bmRead);
    try
      Graphic.LoadFromStream(S);
    finally
      S.Free;
    end;
    Image1.Picture.Assign(Graphic);
  finally
    Graphic.Free;
  end;    
end;
于 2013-08-13T16:58:34.533 に答える