Загрузка изображений в БД

Вопрос о том где хранить изображения – в базе данных или файловой системе – я оставлю за рамками этой записи. Как всегда все зависит от поставленных задач.

Когда в нашей компании решался вопрос о необходимости хранения изображений в базе данных, основным моментом был объем хранимой информации. Исходные 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

Запись опубликована в рубрике Business Intelligence с метками , , . Добавьте в закладки постоянную ссылку.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *