Вопрос о том где хранить изображения – в базе данных или файловой системе – я оставлю за рамками этой записи. Как всегда все зависит от поставленных задач.
Когда в нашей компании решался вопрос о необходимости хранения изображений в базе данных, основным моментом был объем хранимой информации. Исходные 200000 изображений, которые предстояло загрузить в БД занимали около 16 гигабайт, но были при этом сохранены в высоком разрешении. В то же время их предполагалось использовать исключительно при формировании отчетов SSRS, с последующей выгрузкой их в Excel, а для этих целей размера в 150 пикселей по длинной стороне вполне достаточно.
Изначально загрузку предполагалось реализовать с помощью SSIS, но впоследствии было решено написать небольшое приложение на C# и реализовать там простейший GUI, ресайз изображений, загрузку изображений в базу, а оригиналов в высоком разрешении в файловую систему (по желанию пользователя).
На сервере баз данных была создана целевая таблица, содержащая два столбца – ID изображения (ImageID), которое является первичным ключом, и совпадает с именем файла (без расширения), и поля ImageData, типа ‘image’.
Для ресайза и сжатия изображения, использовался код, который был нагло скопипащен отсюда.
private Image resizeImage(Image imgToResize, Size size) { int sourceWidth = imgToResize.Width; int sourceHeight = imgToResize.Height; float nPercent = 0; float nPercentW = 0; float nPercentH = 0; nPercentW = ((float)size.Width / (float)sourceWidth); nPercentH = ((float)size.Height / (float)sourceHeight); if (nPercentH < nPercentW) nPercent = nPercentH; else nPercent = nPercentW; int destWidth = (int)(sourceWidth * nPercent); int destHeight = (int)(sourceHeight * nPercent); Bitmap b = new Bitmap(destWidth, destHeight); Graphics g = Graphics.FromImage((Image)b); g.InterpolationMode = InterpolationMode.HighQualityBicubic; g.DrawImage(imgToResize, 0, 0, destWidth, destHeight); g.Dispose(); return (Image)b; } private void saveJpeg(string path, Bitmap img, long quality) { // Encoder parameter for image quality EncoderParameter qualityParam = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, quality); // Jpeg image codec ImageCodecInfo jpegCodec = getEncoderInfo("image/jpeg"); if (jpegCodec == null) return; EncoderParameters encoderParams = new EncoderParameters(1); encoderParams.Param[0] = qualityParam; img.Save(tempImageFile, jpegCodec, encoderParams); } private ImageCodecInfo getEncoderInfo(string mimeType) { // Get image codecs for all image formats ImageCodecInfo[] codecs = ImageCodecInfo.GetImageEncoders(); // Find the correct image codec for (int i = 0; i < codecs.Length; i++) if (codecs[i].MimeType == mimeType) return codecs[i]; return null; }
После того как размер изображения изменен и оно сохранено во временный файл, происходит загрузка в базу. Здесь нужно учитывать, что ImageID – первичный ключ, поэтому если просто попытаться сделать INSERT, есть вероятность натолкнуться в базе на уже существующий ImageID. Чтобы избежать дополнительных запросов и проверок на этапе выполнения SQL-запроса, я использовал конструкцию TRY…CATCH.
/* Call functions to resize image and save it to temporary location. */ this.img = Image.FromFile(FilePath); img = this.resizeImage(img, new Size(maxWidth, maxHeight)); this.saveJpeg(saveFileDia.FileName, new Bitmap(this.img), jpgQuality); /* Reading image contents into array, it will be used later as a data stream * for SQL query parameter. */ FileStream fs; fs = new FileStream(tempImageFile, FileMode.Open, FileAccess.Read); byte[] picbyte = new byte[fs.Length]; fs.Read(picbyte, 0, System.Convert.ToInt32(fs.Length)); fs.Close(); //Open DB connection and upload pictures. SqlConnection connectDB = new SqlConnection(connectionString); connectDB.Open(); SqlCommand sqlCmd = new SqlCommand(); /* Destination table ImageID column * marked as Primary Key. * In case duplicate value is being uploaded executing query with TRY * and ROLLBACK to avoid DB errors. */ sqlCmd.CommandText = "BEGIN TRY BEGIN TRAN INSERT INTO " + "Images ([ImageID], [ImageData]) VALUES ('" + fileName + "', @pic) " + "COMMIT TRAN END TRY BEGIN CATCH ROLLBACK END CATCH"; SqlParameter picparameter = new SqlParameter(); picparameter.SqlDbType = SqlDbType.Image; picparameter.ParameterName = "pic"; picparameter.Value = picbyte; /* Query got additional paramete @pic which should contain image data stream. */ sqlCmd.CommandType = CommandType.Text; sqlCmd.Connection = connectDB; sqlCmd.Parameters.Add(picparameter); sqlCmd.ExecuteNonQuery(); connectDB.Close();
Ссылки:
Загрузка изображений в базу с помощью SSIS:http://blogs.lessthandot.com/index.php/DataMgmt/DBAdmin/ssis-import-images-table