|
|
Регистрация | << Правила форума >> | FAQ | Пользователи | Календарь | Поиск | Сообщения за сегодня | Все разделы прочитаны |
|
Опции темы | Поиск в этой теме | Опции просмотра |
#1
|
||||
|
||||
Компонент для сжатия изображения
Приветствую вас, форумчане!
Работаю сейчас над базой данных, содержащей графические поля. Большие изображения, это приблизительно 200 - 300 кб, и более 800 х 600 пикселей, записывать в БД нежелательно, ибо чем больше изображение, тем ощутимее сказывается подтормаживание при навигации (это не говоря даже об общем объёме модуля данных). Возникает необходимость предварительного (до записи в БД) сжатия изображения, находящееся в фале или буфере обмена (формат bmp или jpg), а именно нужно уменьшить как его геометрические размеры, так и объём (для jpg регулировать степень сжатия картинки). Существуют ли в природе компоненты, которые могли бы выполнять такие функции? Последний раз редактировалось Guaho, 07.06.2018 в 00:42. |
#2
|
|||
|
|||
Ну, для jpeg есть соотв. модуль. так и называется. достаточно подключить в проект.
Код для изменения размеров картинки тоже достаточно простой, хотя иногда дает не самый лучший результат. Как и сильное сжатие jpeg'а. Но есть другой вариант. Вариант 1. Если есть файл-сервер или доступ к облачному хранилищу, то можно просто файлы картинок писать туда, а в БД сохранять только путь к картинке. Вариант 2. Тут еще зависит от БД. В некоторых базах можно выделить таблицу в отдельное пространство. В этом случае картинки не замедляют операции с осноной таблицей. А вообще, картинки надо грузить по мере необходимости, а не при выборке основного списка. |
#3
|
||||
|
||||
БД работает на "движке" AbsoluteDataBase, все данные находятся в одном файле. Примерное ожидаемое число записей - несколько тысяч. Если изображения не сжимать, размер базы будет порядка нескольких Гиг, а это многовато, да и не нужно. Сверх-высокое качество и разрешение не требуется (база технической направленности). Грузить картинки по мере необходимости - не пойдёт, т.к. нужно сразу видеть изображение, связанное с выбранной записью, это обязательно. Вариант 1 не подойдёт, т.к. это фактически почти то же, что и БД, только вид сбоку (суммарный размер файлов всё равно окажется огромным); а "облако" категорически отпадает. Вариант 2 для моего "движка" не подходит. Остаётся или код, или компонент. Искал среди доступных граф. компонентов сторонних разработчиков - не нашёл ничего путного.
|
#4
|
|||
|
|||
Ну, сжать можно так:
Код:
uses jpeg, math; function CompressBitmapToJpeg(ASource : TBitmap; AWidth, AHeight : Integer) : TJpegImage; var TargetBmp : TBitmap; K : Double; NewWidth, NewHeihg : Integer; begin Result := Nil; TargetBmp := TBitmap.Create; TargetBmp.PixelsPerInch := pf24bit; Try If (ASource.Width <= AWidth) And (ASource.Height <= Height) Then K := 1 Else K := Min(AWidth/ASource.Width, AHeight/ASource.Height); NewWidth := Round(SourceBmp.Width*K); NewHeight := Round(SourceBmp.Height*K); TargetBmp.Width := NewWidth; TargetBmp.Height := NewHeight; TargetBmp.Canvas.StretchDraw(Rect(0,0,NewWidth,NewHeight),ASource); Result := TJpegImage.Create; Result.Assign(TargetBmp); Finally TargetBmp.Free; End; end; function CompressJpeg(ASource : TJpegImage; AWidth, AHeight : Integer) : TJpegImage; var SourceBmp : TBitmap; begin Result := Nil; If (ASource.Width <= AWidth) And (ASource.Height <= AHeight) Then Begin // Do not need to copress jpeg, just copy source to target Result := TJpegImage.Create; Result.Assign(ASource); End Else Begin // Need to compress SourceBmp := TBitmap.Create; Try SourceBmp.Assign(ASource); Result := CompressBitmapToJpeg(SourceBmp,AWidth,AHeigh); Finally SourceBmp.Free; End; end; Перед сохранением установи его свойство CompressionQuality в желаемое значение (чем выше - тем выше качество, но и больше размер). Если правильно помню, то там от 1 до 100. Я бы рекомендовал где-то 60-70. ЗЫ. Код не проверял, так что могут быть очепятки. |
Этот пользователь сказал Спасибо lmikle за это полезное сообщение: | ||
Guaho (07.06.2018)
|
#5
|
||||
|
||||
Благодарю за приведённый код, он указал мне направление. Я решил не играться с качеством jpg, а просто ужимать размеры независимо от типа изображения. Проведённые эксперименты показали, что такой подход вполне приемлем: урезание размеров уже даёт нужный результат по весу файла даже для bmp, и следовательно, для jpg, и не нужно играться со степенью его компрессии.
В качестве промежуточного хранилища "входящего" изображения я использовал компонент TDBImageEh из библиотеки EhLib (имя im0). Вот что получилось, может пригодится кому-нибудь: Код:
{ Функция загрузки изображения из буфера обмена и при необходимости уменьшения его размеров.} function Tdm.PictureLoadFromClipboard():TBitmap; begin try im0.Picture.Assign(Clipboard); except Application.MessageBox('Данные в буфере обмена не являются изображением! ' + #13 + 'В это поле БД можно вставить только изображение.', ' Предупреждение', MB_ICONWARNING + MB_OK); Result := nil; exit; end; PictureResize; Result := im0.Picture.Bitmap; end; { Функция загрузки изображения из файла и при необходимости уменьшения его размеров.} function Tdm.PictureLoadFromFile():TBitmap; begin if opPd1.Execute then begin try im0.Picture.LoadFromFile(opPd1.FileName); im0.CopyToClipboard; im0.Picture.Assign(Clipboard); except Application.MessageBox('Не удалось загрузить изображение в БД. ' + #13 + 'Возможно, оно имеет неверный или неподходящий формат.', ' Предупреждение', MB_ICONWARNING + MB_OK); Result := nil; exit; end; end; PictureResize; Result := im0.Picture.Bitmap; end; { Процедура уменьшения размеров изображения, уже находящегося в компоненте im0. Результат сжатия помещается туда же, в im0. } procedure Tdm.PictureResize; var sW, sH, tW, tH, max: Integer; TBM: TBitmap; begin max := fm_param._eMaxPictureSize.Value; sW := im0.Picture.Bitmap.Width; sH := im0.Picture.Bitmap.Height; if ((sW > max) or (sH > max)) then begin if sW > sH then begin tW := max; tH := Trunc(sH * max / sW); end else begin if sW < sH then begin tH := max; tW := Trunc(sW * max / sH); end else//sW = sH begin tH := max; tW := max; end; end; end else begin tH := sH; tW := sW; end; TBM := TBitmap.Create; TBM.Width:= tW; TBM.Height:= tH; TBM.Canvas.StretchDraw(rect(0, 0, TBM.Width, TBM.Height), im0.Picture.Bitmap); im0.Picture.Bitmap.Assign(TBM); TBM.Free; end; Последний раз редактировалось Guaho, 26.06.2018 в 19:22. |