# Native Code > برنامه نویسی با C > برنامه نویسی با Borland C++‎ Builder > سوال: ذخیره کردن عکس در sql server

## C++‎Builder

سلام، خوبین؟
چه جوری می تونم یه عکس رو تو پایگاه داده SQL SEREVR دخیره کنم؟ تو سمت C++‎BUILDER از چه نوعی استفاده کنم؟

----------


## sasan_vm

سلام
به روشهای مختلف می شود این کار را انجام داد فرضا اگر برای ارتباط با پایگاه داده از ADO استفاده کرده باشید می توانید چنین کدی را بکار برید:


 TFileStream * sImage;
 TStream     * sField;
 sImage = new TFileStream("..\\MyPic.bmp", fmOpenRead);
 ADOQuery1->Append();
 __try
 {
  sField = ADOQuery1->CreateBlobStream(ADOQuery1->FieldByName("My_Field"), bmWrite);
  sField->CopyFrom(sImage, sImage->Size);
 }
 __finally
 {
  delete sField;
 }
 ADOQuery1->Post();
 delete sImage;


در روش بالا با CreateBlobStream توسط یک Stream مستقیما به Field تصویر در بانک اطلاعاتی متصل میشوید با تغییر پارامتر دوم می توانید این Stream را برای read, write یا read/write بکار برید.
نکته: قبل از فراخوانی تابع Post حتما باید stream ایجاد شده حذف گردد.

----------


## C++‎Builder

سلام
با تشکر،
با استفاده از روشی که گفتین تونستم عکس رو ذخیره کنم، ولی نمی تونم بازیابیش کنم. چه جوری می شه بازیابی کرد؟

----------


## sasan_vm

سلام
اگه فایل تصویری bmp هست به روش قبل یک stream به فیلد تصویری ایجاد کنید با پارامتر bmRead و یک
TImage روی فرم بذارید و با این کد تصویر را load کنید:

Image1->Picture->Bitmap->LoadFromStream(Stream);

----------


## C++‎Builder

سلام
خیلی ممنون، مشکلم حل شد.

----------


## behzadboloori

اما اگر فایل ا ز جنس Jpeg بود باید چکار کنم؟

----------


## sasan_vm

#include <Jpeg.hpp>

...

TJPEGImage  * jpgImg;
...
jpgImg = new TJPEGImage;
jpgImg->LoadFromStream(Stream);
Image1->Picture->Assign(jpgImg);

----------


## behzadboloori

بازم ممنون
ولی اگه بخوام به کاربر اجازه بدم بیش از یک نوع فایل رو آپلود کنه، زمان بازیابی چطوری تشخیص بدم که فایل از چه نوعیه؟ تا یه استریم از همون نوع ایجاد کنم. البته من یه کد دلفی براش پیدا کردم ولی نمیتونم تبدیل به سی بکنم

*procedure* TForm1.btnLoadClick(Sender:  TObject);
 *var*
 s: TStream;
 buf: word;
 gf: TGraphic;
 *begin*
 Query1.SQL.Text := 'SELECT img FROM htest';
 Query1.Open;
 Query1.First;
 s := Query1.CreateBlobStream(Query1.FieldByName('img'), bmRead);
 *try*
 *if s.read(buf, sizeof(buf)) <> sizeOf(buf)* *then  exit;*
   s.Position := 0;
 *if* buf = $D8FF *then*
     gf := TJPEGImage.Create
   else *if* buf = $4D42 *then*
     gf := TBitmap.Create
   else *if* buf = $CDD7 *then*
     gf := TMetafile.Create
   else *if* buf = 0 *then* 
     gf := TIcon.Create;
 *try*
     gf.LoadFromStream(s);
     Image1.Picture.Graphic := gf;
 *finally*
     gf.Free;
 *end*;
 *finally*
   s.Free;  // must free stream
 *end*;
 *end*;

راستش من اون خطی رو که قرمز کردم اصلا نمیفهمم. میشه برام توضیح بدین

----------


## behzadboloori

البته در مورد ادرسهایی که قرمز شده هم  توضیح بدین *if* buf = $D8FF *then*
     gf := TJPEGImage.Create
   else *if* buf = $4D42 *then*
     gf := TBitmap.Create
   else *if* buf = $CDD7 *then*
     gf := TMetafile.Create

----------


## sasan_vm

> راستش من اون خطی رو که قرمز کردم اصلا نمیفهمم. میشه برام توضیح بدین
> [/LEFT]


فایلهای تصویری (gif, bmp, jpg, ...)  یک امضاء دارند که در 2 بایت یا 4 بایت اول فایل ذخیره میشود
که با تست آن می توانید متوجه شوید که آن فایل چه قالب بندی دارد. در مثالی که ارسال کردید از
همین روش استفاده شده است اگر از یک Binary Editor  مانند winhex  استفاده کنید و با آن این فایلهای گرافیکی را باز کنید متوجه میشوید 2 بایت اول فایلهای گرافیکی ذیل به این صورت است:

bmp:  0x424D  (BM)
jpg: 0xFFD8
gif: 0x4749463839  (GIF98))
.
.


در کد قرمز رنگ به اندازه حافظه ای که برای word  در دلفی ذخیره می شود (2 یا 4 بایت وابسته به سیستم عامل و کمپایلر) از stream  می خواند تابع read , write  در stream همیشه تعداد بایت نوشته/خوانده شده را برمی گردانند تا اگر خطایی رخ داده باشد بتوان چک کرد.

در کد معادل در C  چون می خواهیم 2 بایت را چک کنیم بهتر است دقیقا مشخص کنیم
2 بایت از stream  بخواند تا از خطای اندازه متغیر ها در سیستم عامل و کمپایلر جلوگیری شود.
بعد از این کد متغیر buf حاوی 2 بایت اول stream  است و می توانید آن را با مقادیر امضاء فایلهای
گرافیکی مقایسه کنید.


if s.read(buf, sizeof(buf)) <> sizeOf(buf) then exit

short int buf, szie = 2; 

if (s->read(&buf, size) != size)
	exit(0);

----------


## behzadboloori

اولا شما گفتین که در سی اون اکضا دوبایتیه ولی با کد زیر
bmp:  0x424D  (BM)
jpg: 0xFFD8
که البته در مورد gif به نظر میرسه که بیشتر باشه
gif: 0x4749463839  (GIF98))
 مشکل اینه که من همین gif  رو نمیتونم توی Image نشون بدم


در ضمن برای فایلهای دیگه ای مثل tif, png من میتونم اونا رو توی بانک اطلاعاتی ذخیره کنم ولی زمانی که میخوام object لازم رو برای خوندنشون ایجاد کنم چیز مناسبی رو پیدا نمیکنم.
                           TGraphic       * sGraphic;
if     (*buf==0xD8FF)
        sGraphic=new TJPEGImage;
else if(*buf==0xCDD7)
       sGraphic=new TMetafile;
جایی هست که من بتونم برای فرمتهای مختلف عکس ابجکتهای مناسب پیدا کنم

----------


## sasan_vm

> اولا شما گفتین که در سی اون اکضا دوبایتیه ولی با کد زیر
> bmp:  0x424D  (BM)
> jpg: 0xFFD8
> که البته در مورد gif به نظر میرسه که بیشتر باشه
> gif: 0x4749463839  (GIF98))
>  مشکل اینه که من همین gif  رو نمیتونم توی Image نشون بدم
> 
> 
> در ضمن برای فایلهای دیگه ای مثل tif, png من میتونم اونا رو توی بانک اطلاعاتی ذخیره کنم ولی زمانی که میخوام object لازم رو برای خوندنشون ایجاد کنم چیز مناسبی رو پیدا نمیکنم.
> ...


- در bmp , jpg  امضا 2 بایتی هست (این ربطی به زبان نداره) ولی همان طور که نوشتم در gif امضا بیشتر هست (GIF98)
  احتمالا فکر نمی کنید که 0x424d یا 0xffd8  بیشتر از 2 بایت باشه  :لبخند گشاده!: 

- کد لود کردن فایل gif  مانند jpg هست فقط باید object را بشناسید البته این object توسط CodeGear ارائه نشده و نویسنده آن Anders Melander هست:

#include <GIFimg.hpp>
...

TGIFImage	* gifImg;
gifImg = new TGIFImage;
..
gifImg->LoadFromStream(Stream);
Image1->Picture->Assign(gifImg);


فایلهای png , tiff در bcb  پشتیبانی نمی شوند شما می توانید از object های آماده استفاده کنید یا خودتان کد بنویسید. یکی از بهترین component گرافیکی 2D hicomponents هست.

----------


## behzadboloori

من با استقاده از کلاس زیر تونستم gif رو لود کنم
#include <axctrls.hpp>

----------


## ghasemweb

مرسی از مطالبتون استفاده کردیم

----------

