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.Graphic使用有效的TGraphic派生对象初始化属性,因此该属性很可能会nil导致崩溃。

此外,当保存TPicture.Graphic到 时TMemoryStream,您在将图形保存到数据库时会跳过图形的第一个字节。所有字节都很重要,所以不要跳过任何一个。

假设您的图像是专门的 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 之外的其他格式,那么您还需要将图像类型存储在数据库中,以便您可以将其读回并实例化正确的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 为您提供一个TStream针对访问 ADO blob 数据进行了优化的对象,例如:

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 回答