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

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

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

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

Сообщение GAMER » 07.12.2010 02:19:00

Тема писана-переписана. Но.
Я работаю с MySQL напрямую, не используя никаких компонент. Все запросы отправляются строкой. По-этому те ответы, что я нашел, мне не подходят.
Как TImage преобразовать в AnsiString или PChar? Пробовал через TStream, но что-то не получается.
Последний раз редактировалось GAMER 11.12.2010 15:33:56, всего редактировалось 1 раз.
Аватара пользователя
GAMER
энтузиаст
 
Сообщения: 627
Зарегистрирован: 06.08.2008 13:41:07
Откуда: Ужгород-Днепр, Украина

Re: Картинку в блоб-поле

Сообщение coyot.rush » 07.12.2010 02:21:48

Может через Base64 http://ru.wikipedia.org/wiki/Base64 если все хранить AnsiString
Аватара пользователя
coyot.rush
постоялец
 
Сообщения: 309
Зарегистрирован: 14.08.2009 08:59:48

Re: Картинку в блоб-поле

Сообщение stikriz » 07.12.2010 10:22:16

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

Код: Выделить всё
var Buff: PChar;
      Tmp: TMemoryStream;
...
Image.SaveToStream(Tmp);
...
GetMem(Buff^, Tmp.Size);
Tmp.Position:=0;
Tmp.Write(Buf^, Tmp.Size);
...


Что-то в этом роде.
Аватара пользователя
stikriz
энтузиаст
 
Сообщения: 612
Зарегистрирован: 15.03.2006 09:37:47

Re: Картинку в блоб-поле

Сообщение GAMER » 07.12.2010 13:43:46

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

Re: Картинку в блоб-поле

Сообщение stikriz » 07.12.2010 14:59:59

Не только в PChar, но и в string можно пихать нулевые байты, тем более, что сейчас там utf-8...
В случае с PChar не забудьте FreeMem.
Аватара пользователя
stikriz
энтузиаст
 
Сообщения: 612
Зарегистрирован: 15.03.2006 09:37:47

Re: Картинку в блоб-поле

Сообщение GAMER » 07.12.2010 15:16:13

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

Re: Картинку в блоб-поле

Сообщение stikriz » 07.12.2010 15:58:27

Какие строки?
Вы через API с MySQL работаете?
Нельзя-ли показать заголовок функции, которая апдейтит блоб?
Что-то я подозреваю, что что-то не так...
Аватара пользователя
stikriz
энтузиаст
 
Сообщения: 612
Зарегистрирован: 15.03.2006 09:37:47

Re: Картинку в блоб-поле

Сообщение GAMER » 07.12.2010 16:18:01

Код: Выделить всё
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)'
Аватара пользователя
GAMER
энтузиаст
 
Сообщения: 627
Зарегистрирован: 06.08.2008 13:41:07
Откуда: Ужгород-Днепр, Украина

Re: Картинку в блоб-поле

Сообщение stikriz » 07.12.2010 16:38:22

mysql_escape_string() - экранирует специальные символы в строке, т.е. нечитабельные в запросе.
Аватара пользователя
stikriz
энтузиаст
 
Сообщения: 612
Зарегистрирован: 15.03.2006 09:37:47

Re: Картинку в блоб-поле

Сообщение Vadim » 07.12.2010 16:43:18

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

Код: Выделить всё
StrCat(PChar1, PChar2);

;)
Vadim
долгожитель
 
Сообщения: 4112
Зарегистрирован: 05.10.2006 08:52:59
Откуда: Красноярск

Re: Картинку в блоб-поле

Сообщение stikriz » 07.12.2010 16:46:05

И посмотрите getBlobHandle
Вообще, я привык к тому как в FireBird.
Поэтому, замолкаю - тут я не большой знаток.
Аватара пользователя
stikriz
энтузиаст
 
Сообщения: 612
Зарегистрирован: 15.03.2006 09:37:47

Re: Картинку в блоб-поле

Сообщение GAMER » 07.12.2010 17:11:25

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

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

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

Сообщение GAMER » 11.12.2010 15:33:06

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

Сначала о граблях.
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;       
Аватара пользователя
GAMER
энтузиаст
 
Сообщения: 627
Зарегистрирован: 06.08.2008 13:41:07
Откуда: Ужгород-Днепр, Украина


Вернуться в Lazarus

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 13

Рейтинг@Mail.ru