I have a table like below
IMAGEID COVERPAGEIMAGE IMAGENAME
------------------------------------------------
LME111201908576 0x89504E470D0A1... NULL
I want to convert all the COVERPAGEIMAGE is of varbinary(max) datatype to a png/jpeg image and update the name in IMAGENAME using a SQL query.
The table includes almost 10000 rows of data. I couldn't find a faster way to do it yet any help or guidance would be appreciated.
There is File.WriteAllBytes method that could help to create file from blob data. Example,
...
using (var r = cmd.ExecuteReader())
{
while (r.Read())
{
File.WriteAllBytes("C:\temp\" + (string)r["IMAGEID"]+ ".png",
(byte[])r["COVERPAGEIMAGE"]);
}
}
Assigning IMAGENAME will depend on how target file names will look like. If filename will be always equal to IMAGEID+".png" like in example above, you might not need that column at all.
Same can be done with only sql: fastest way to export blobs from table into individual files
Related
We read a tab delimited file into a DataTable with the following code.
//read the uploaded file...
var records = File.ReadAllLines(Server.MapPath("~/UploadFiles/") + Session.SessionID + "/orderEDI.txt").ToList();
//load the data into the temporary table...
records.ForEach(record => loadTable.Rows.Add(record.Split((char)9)));
This works just fine providing there are not more tabs in the file than there are columns in the DataTable.
I'm looking to find out if there's a way I can limit the number of columns it reads from the file. Or any other suggestions around this issue. It must read an absolute minimum of 10 columns (and ideally, only 10)
I build the DataTable and add columns to it before this load occurs. Would it be better to not add columns and just load the file into the DataTable and then read the table by column index rather than name?
Really not sure which way to go and would appreciate some experienced opinions.
Thanks
Since split results in an array, why don't you just use Take(10)?
//read the uploaded file...
var records = File.ReadAllLines(Server.MapPath("~/UploadFiles/") + Session.SessionID + "/orderEDI.txt").ToList();
//load the data into the temporary table...
records.ForEach(record => loadTable.Rows.Add((record.Split((char)9)).Take(10)));
I stored the image path file as text into the database instead of using OLE Object. Now I want to know how to retrieve the image path from the database and load the image into the Crystal Report.
The image path is stored something like this C:\Users\HPLaptop\Desktop\Folder\ImageFile.jpg and I want the crystal report to load the image using this path file.
Report Schema:
We all know that we need to provide a schema for the crystal repot. Here is an XML view of the report schema that we are going to supply for the report.
BLOB field:
In order to add an image to the crystal report (considering the image field is coming from the database) we need to have a BLOB field in the schema. When you want to store images, documents or different custom types in the database you use a BLOB field. BLOB stands for Binary Large Object.
If you inspect this schema we can see that we have a table called "Images" and two columns "path" and "image". "image" column is type Base64 Binary. This is our BLOB field.What we are going to do in our program is when the user selects the image to upload we store that image in a BLOB field as a stream of bytes and then supply that dataset to the report.
CreateTable() method will illustrate how to generate this schema in the program.
Generating the schema for the report:
There are other ways you can create the schema but this will give you a clearer idea about the column fields.
Creating the table:
private void CreateTable()
{
//create a new data set.
this.DsImages = new DataSet();
//create a new table with two columns and add the table to the
dataset
DataTable ImageTable = new DataTable("Images");
//in here the "path" column is not really needed. Image column is
just enough.
ImageTable.Columns.Add(new DataColumn("path",typeof(string)));
//Important note
//Note the type of the image column. You want to give this column
as a blob field to the crystal report.
//therefore define the column type as System.Byte[]
ImageTable.Columns.Add(new DataColumn("image",typeof(System.Byte[])));
this.DsImages.Tables.Add(ImageTable);
}
If you notice the "image" column you can see that the type of that column is System.Byte[]. This is pretty straight forward. Just create a table with two columns. Then add it to the dataset. Now you can create the schema using this line:
this.DsImages.WriteXmlSchema(#"c:\temp\ImagesSchema.xsd");
Once we have the schema ready we can provide it to the crystal report.
Image 1:
Inspect the Image 1, in the field explorer we can see Images table and the two columns path and image. When you drag the image column onto the report you can see the type of that field is IBlobFieldObject. These fields will read a stream of bytes and convert it back to an image. So our task is pretty much done. The code below shows you how it can save the image as a stream of bytes in the BLOB field.
private void openFileDialog1_FileOk(object sender, System.ComponentModel.CancelEventArgs e)
{
try
{
//get the image file into a stream reader.
FileStream FilStr = new FileStream(this.openFileDialog1.FileName, FileMode.Open);
BinaryReader BinRed = new BinaryReader(FilStr);
//Adding the values to the columns
// adding the image path to the path column
DataRow dr = this.DsImages.Tables["images"].NewRow();
dr["path"] = this.openFileDialog1.FileName;
//Important:
// Here you use ReadBytes method to add a byte array of the image stream.
//so the image column will hold a byte array.
dr["image"] = BinRed.ReadBytes((int)BinRed.BaseStream.Length);
this.DsImages.Tables["images"].Rows.Add(dr);
FilStr.Close();
BinRed.Close();
//create the report object
DynamicImageExample DyImg = new DynamicImageExample();
// feed the dataset to the report.
DyImg.SetDataSource(this.DsImages);
this.crystalReportViewer1.ReportSource = DyImg;
}
catch(Exception er)
{
MessageBox.Show(er.Message,"Error");
}
}
You write this in the FileOk method of the openFileDialog. You use the BinaryReader.ReadBytes method to read the byte array.
dr["image"] = BinRed.ReadBytes((int)BinRed.BaseStream.Length);
I have some simple entity which now needs to have a Profile image. What is the proper way to do this? So, it is 1 to 1 relationship, one image is related only to one entity and vice versa. This image should be uploaded through webform together with inserting related entity.
If anyone can point me to the right direction how to persist images to the db and related entity will be great.
Just a side comment: I think is not a good idea to store images in db.
In general is not a good idea store images in db as dbs are designed to store text not big binary chunks. Is much better to store paths for images and have images in a folder. If you want to get sure of 1 to 1 relationship name image with ID of entity (1323.jpg).
If you want to have image paths you should follow some guidelines (In general code defensively):
On upload of image check that image is valid (even made a binary check of image header)
Don't allow to overwrite an existing image in case of a INSERT of a new entity.
Name images as primary key (1.jpg, 2.jpg)
On load of image don't assume that image is going to be there.
Do not allow (if possible) manual interaction with images (No remoting in machine and copying images from one place to other). Manual interaction can cause inconsistencies.
But I assume that for some reason you should do it. So in order to achieve what you want:
DB design
Create a binary column (binary or varbinary) in your table
It is better if you create it in a different table with 1-1 relationship. However the idea is avoiding to load image when hydrating entity. Use a lazy load approach to load your image only when you want.
You have to avoid to load images when you make a big select (for example if you want to load all your entities in a combo avoid SELECT * From whatever) as it will load thousands of images for nothing. As I said this can be done by having images in a different table, or loading only proper columns in SELECT or by making lazy load. (Or even better by NOT having images in DB, only paths)
C# Code
Use BynaryReader to read it
User Byte array to store it
Check this link for code example: http://www.codeproject.com/Articles/21208/Store-or-Save-images-in-SQL-Server
The code is trivial but why the DB?
If this is a website why not save it to a location on disk where you can easily reference it?
Databases are optimised to store data of a known size and relatively small size. Youre image will most likely be more than 8KB in length (mearning its a MAX datatype).
The image will be stored on a separate row/page from your "profile".
Personally I'd save the images in a known folder and use the id for the image name. For profiles that don't have an image and use a standard gif or similar, probably keep it simple / trim by having simlinks/hardlinks of the profile id to the common gif.
public class Profile
{
public int Id {get;}
public string Name {get; private set;}
public Image Picture {get; private set;}
public void Save()
{
using (var connection = new SqlConnection("myconnectionstring"))
using (var command = new SqlCommand("", connection))
{
command.CommandText =
"UPDATE dbo.TblProfile " +
"SET " +
"Name = #name, " +
"Picture = #picture " +
"WHERE ID = #id";
command.Parameters.AddWithValue("#name", Name);
command.Parameters.AddWithValue("#picture", Picture);
command.Parameters.AddWithValue("#id", Id);
command.ExecuteNonQuery();
}
}
}
I think following link would give you the solution,
Upload Image and Save in DB
In my database I have stored images in the "image" data type, showing up as a binary code.
I now want to retrieve all images from one column and diplay them on a asp.net page with C#.
databaseDataContext db = new databaseDataContext();
var images = from Picture p in db.Pictures
select p.pictureThumb;
then I use this:
foreach (Picture p in images)
{
galleryImages.Controls.Add(p);
}
But that doesn't work because Binary can't be converted to Picture. I have Googled this and found that I have to cast to Byte and then to image? I can't find examples on how to do that though.
This should do it:
databaseDataContext db = new databaseDataContext();
var images = from p in db.Pictures
select Image.FromStream(new MemoryStream(p.pictureThumb.ToArray());
foreach (Image image in images)
{
galleryImages.Controls.Add(image);
}
Note that Image.FromStream takes ownership of the stream - it's only a MemoryStream anyway, but do make sure that you dispose of the image, for various reasons.
EDIT: Ah... I hadn't realised that this was for ASP.NET. That makes things harder - because the HTML is going to contain URLs, and then you'll need to be able to fetch the data later.
Does a picture have an ID of some kind? If so, fetch that instead of the actual data, and then set up a URL which is able to serve any thumbnail based on the ID (by fetching it from the database and just serving it with an appropriate content type).
i'm working on Linq To Sql,WPF and i have a database now i need to save some picture in the database but i don't know which is the correct datatype to save the pictures Database(this database would be connect from 10 users in the same time).
Can you point me in the right way to overcome this step?
If i didn't wrong it is not a good idea to save pictures in the database but if you can advice me a better method i will apply it.
Thanks so much for your time.
Nice Regards
You can use a 'varbinary(MAX)' or 'image' column type. Linq2Sql will auto-generate a class that uses a Binary object to wrap your image. The Binary object is just a wrapper around a byte[].
myObject.Image = new Binary(imageByteArray);
Store your picture as a blob, the variable defined in your class containing the image could be a byte[] stream. Alternatively you just store a reference to the picture in the database and store the image on a file server.
Typically you will use a varbinary(max) -or less than max- on the database side and you will use a byte[] type in your class.
There's a lot of heated debates that occur when people talk about this, I would like to note that you might want to consider storing that path to a network folder in the database.
The disadvantage of storing the actual image in the database is that all those bytes have to get sent back and forth through a sql query and if those images are large you will be increasing the size of your db substantially. along with the weird things that were mentioned above.
Anyways I don't want to open up a can of worms, just wanted to show an alternative.
UPDATE:
Something like this:
public partial class LinqClass
{
public string ImagePath { get; set; }
public System.Drawing.Image Picture
{
get
{
return System.Drawing.Image.FromFile(ImagePath);
}
}
}
where ImagePath is the actual column in the db that you are saving the file path to. This doesn't have the code to save the file (something like File.Save(ImagePath) etc. but it's a start.
I've never done it with Linq, but we used a b64 conversion for the image, then a clob datatype. Then reverse the b64 when you want to view the image.