(Решено) Картинку в блоб-поле

Вопросы программирования и использования среды Lazarus.

Модератор: Модераторы

Ответить
Аватара пользователя
GAMER
энтузиаст
Сообщения: 627
Зарегистрирован: 06.08.2008 13:41:07
Откуда: Ужгород-Днепр, Украина
Контактная информация:

(Решено) Картинку в блоб-поле

Сообщение GAMER »

Тема писана-переписана. Но.
Я работаю с MySQL напрямую, не используя никаких компонент. Все запросы отправляются строкой. По-этому те ответы, что я нашел, мне не подходят.
Как TImage преобразовать в AnsiString или PChar? Пробовал через TStream, но что-то не получается.
Последний раз редактировалось GAMER 11.12.2010 14:33:56, всего редактировалось 1 раз.
Аватара пользователя
coyot.rush
постоялец
Сообщения: 309
Зарегистрирован: 14.08.2009 08:59:48

Сообщение coyot.rush »

Может через Base64 http://ru.wikipedia.org/wiki/Base64 если все хранить AnsiString
Аватара пользователя
stikriz
энтузиаст
Сообщения: 612
Зарегистрирован: 15.03.2006 08:37:47

Сообщение stikriz »

GAMER писал(а):Как TImage преобразовать в AnsiString или PChar?

Код: Выделить всё

var Buff: PChar;
      Tmp: TMemoryStream;
...
Image.SaveToStream(Tmp);
...
GetMem(Buff^, Tmp.Size);
Tmp.Position:=0;
Tmp.Write(Buf^, Tmp.Size);
...


Что-то в этом роде.
Аватара пользователя
GAMER
энтузиаст
Сообщения: 627
Зарегистрирован: 06.08.2008 13:41:07
Откуда: Ужгород-Днепр, Украина
Контактная информация:

Сообщение GAMER »

А как быть с нулевыми байтами в середине? Или в случае выделения памяти на размер потока, это не играет роли?
Аватара пользователя
stikriz
энтузиаст
Сообщения: 612
Зарегистрирован: 15.03.2006 08:37:47

Сообщение stikriz »

Не только в PChar, но и в string можно пихать нулевые байты, тем более, что сейчас там utf-8...
В случае с PChar не забудьте FreeMem.
Аватара пользователя
GAMER
энтузиаст
Сообщения: 627
Зарегистрирован: 06.08.2008 13:41:07
Откуда: Ужгород-Днепр, Украина
Контактная информация:

Сообщение GAMER »

В PChar нулевые байти пихаются хорошо, уже проверил. Сейчас ищу, как соединять такие строки.
Спасибо за подсказки.
Аватара пользователя
stikriz
энтузиаст
Сообщения: 612
Зарегистрирован: 15.03.2006 08:37:47

Сообщение stikriz »

Какие строки?
Вы через API с MySQL работаете?
Нельзя-ли показать заголовок функции, которая апдейтит блоб?
Что-то я подозреваю, что что-то не так...
Аватара пользователя
GAMER
энтузиаст
Сообщения: 627
Зарегистрирован: 06.08.2008 13:41:07
Откуда: Ужгород-Днепр, Украина
Контактная информация:

Сообщение GAMER »

Код: Выделить всё

Function QuerryP(Const MySock : PMYSQL; Const SelStr: PChar; Out MySQLErrMsg : AnsiString): boolean;
Begin
 Result := True;
 if (mysql_query(MySock,SelStr) > 0) then
  begin
   MySQLErrMsg := 'Query failed. '+ mysql_error(MySock);
   Result := False;
   exit;
  end;
End;


Добавлено спустя 6 минут 19 секунд:
Как правильно к одной строке PChar добавить другую строку PChar, если и там и там есть нулевые байты?
Нужно сформирвоать строку типа 'insert into foto set unsprava=1, foto=CAST("'+Buff+' as binary)'
Аватара пользователя
stikriz
энтузиаст
Сообщения: 612
Зарегистрирован: 15.03.2006 08:37:47

Сообщение stikriz »

mysql_escape_string() - экранирует специальные символы в строке, т.е. нечитабельные в запросе.
Vadim
долгожитель
Сообщения: 4112
Зарегистрирован: 05.10.2006 08:52:59
Откуда: Красноярск

Сообщение Vadim »

GAMER писал(а):Как правильно к одной строке PChar добавить другую строку PChar, если и там и там есть нулевые байты?

Код: Выделить всё

StrCat(PChar1, PChar2);

;)
Аватара пользователя
stikriz
энтузиаст
Сообщения: 612
Зарегистрирован: 15.03.2006 08:37:47

Сообщение stikriz »

И посмотрите getBlobHandle
Вообще, я привык к тому как в FireBird.
Поэтому, замолкаю - тут я не большой знаток.
Аватара пользователя
GAMER
энтузиаст
Сообщения: 627
Зарегистрирован: 06.08.2008 13:41:07
Откуда: Ужгород-Днепр, Украина
Контактная информация:

Сообщение GAMER »

Что-то у меня strcat криво работает, если данные бинарные. Или это watch-окно криво показывает?

Добавлено спустя 5 часов 46 минут 22 секунды:
mysql_real_escape_string немного помогает, но проблема в том, что строки работают в UTF8, и на некоторых байтах становится вопросительный знак, на что собственно и ругается майСКЛ.
Аватара пользователя
GAMER
энтузиаст
Сообщения: 627
Зарегистрирован: 06.08.2008 13:41:07
Откуда: Ужгород-Днепр, Украина
Контактная информация:

Сообщение GAMER »

И так, получилось :) Может кому-то пригодится.

Сначала о граблях.
1. Основные грабли - это нулевые символы в данных. При работе с PChar, AnsiString получаем кучу гемора.
2. Нужно быть очень аккуратными при работе с MemoryStreamN.Write
3. Нужно аккуратно использовать mysql_real_escape_string. Оно преобразовывает все, в том числе и те кавычки, которые не нужно було :) Долго с этим возился :)
4. При анализе данных в watch-окне, в строках фигурируют вопросительные знаки. Это все UTF8. Нужно побайтно просматривать.

Что нужно (желательно) использовать.
1. В запросах делаем CAST("...'" as binary)
2. Служебные символы Мускуля обходим с помощью mysql_real_escape_string, но аккуратно.
3. Размер вывода получаем через mysql_fetch_lengths(PResult) (другие функции обрезают длину по нулевому символу.)

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

Добавлено спустя 6 часов 10 минут 48 секунд:
Re: (Решено) Картинку в блоб-поле
Обещаный код:

Подпрограмма записи в блоб-поле:

Код: Выделить всё

Function QuerryP(Const MySock : PMYSQL; Const SelStr: PChar; Const len: longint; Out MySQLErrMsg : AnsiString): boolean;
Begin
 Result := True;
 if (mysql_real_query(MySock,SelStr, len) <> 0) then
  begin
   MySQLErrMsg := 'Query failed. '+ mysql_error(MySock);
   Result := False;
   exit;
  end;
End;   


Подпрограмма форимрования запроса для записи:

Код: Выделить всё

procedure TFrmWebcam.Button2Click(Sender: TObject);
const S1='insert into foto set unsprava=1, foto=CAST("';
      S2='" as binary)';
var
  Stream: TMemoryStream;
  w1, w2: Pchar;
begin
// Image1.Picture.Jpeg.SaveToFile('test.jpg');
 Stream := TMemoryStream.Create;
// Image1.Picture.Jpeg.SetSize(10,10);
 Image1.Picture.Jpeg.SaveToStream(Stream);  // Сохраняем Jpeg-картинку в поток

 Stream.Position:=0;
 GetMem(w1, Stream.Size);
 Stream.Read(w1[0], Stream.Size); // Читаем с потока  в переменную w1
 GetMem(w2, 2*Stream.Size);
 mysql_real_escape_string(MySockW, w2, w1, Stream.Size); //Делаем читабельную для Мускуля строку
 Stream.Free;
 if not QuerryP(MySockW, Pchar(s1+w2+s2), Length(s1+w2+s2), ErrMsg) then ShowMessage(ErrMsg);
 Freemem(w1);Freemem(w2);
end;   


Подпрограмма чтения блоб-поля:

Код: Выделить всё

Function SelectToMemoryStream(Const Mysock: PMYSQL; Const SelStr: AnsiString; Var MemoryStreamN: TMemoryStream; Out VMySQLErrMsg : AnsiString): boolean;
Var FieldCount: Integer;
    PCurrentRow: {$IFDEF FPC}MySQL_Row{$ELSE}PMySQL_Row{$ENDIF};
    PResult: Pointer;
    RecordCount:  Integer;
    LenArray: PDWord;
Begin
 Result := True;
 if (mysql_query(MySock,PChar(SelStr)) > 0) then
 begin
   VMySQLErrMsg := 'Ошибка запроса. '+ mysql_error(MySock);
   Result := False;
   exit;
 end;
 PResult:= MySQL_Use_Result(MySock); {Can be called for select and none-select. Returns nil if storing failed or if query was none-select}
 if PResult = nil then
 begin
   if MySQL_Field_Count(MySock) = 0 then {It was a none-select}
   begin
      VMySQLErrMsg := 'Запрос не возвратил поля. '+chr(10)+chr(13)+
                      'Обработано '+IntToStr(MySQL_Affected_Rows(MySock))+' записей.';

     Result := False;
     exit;
   end
   else {It was a select query, but an error has occured}
   begin
     VMySQLErrMsg := 'Ошибка запроса. '+ mysql_error(MySock);
     Result := False;
     exit;
   end;
 end;
 // else Result is not null - receiving data
 try
  // Fields count receiving
  FieldCount:= MySQL_Num_Fields(PResult);
  if (FieldCount=0) or (FieldCount>1) then
  begin
   VMySQLErrMsg := 'Запрос не возвратил поля либо полей больше 1';
   Result := False;
   exit;
  end;
  // Record data receiving
  RecordCount := 0;
  PCurrentRow:= MySQL_Fetch_Row(PResult);
  LenArray:=mysql_fetch_lengths(PResult);
  while PCurrentRow <> nil do
  begin
    Inc(RecordCount);
    MemoryStreamN.Position:=0;
    MemoryStreamN.Write(PCurrentRow[0][0], LenArray[0]);
    PCurrentRow:= MySQL_Fetch_Row(PResult);
  end;
  finally
    MySQL_Free_Result(PResult);
    PResult:=nil;
    PCurrentRow:=nil;
  end;
End;     


Подпрограмма формирования запроса и вставки картинки:

Код: Выделить всё

procedure TFrmWebcam.Button3Click(Sender: TObject);
Var  Stream: TMemoryStream;
Begin
  Stream := TMemoryStream.Create;
  if not SelectToMemoryStream(MySockW,
  'select CAST(foto as binary) from foto',
  Stream, ErrMsg) then
    ShowMessage(ErrMsg)
  else
  begin
    Stream.Position:=0;
    Image1.Picture.Jpeg.LoadFromStream(Stream);
  end;
  Stream.Free;
End;       
Ответить