Страницы

Поиск по вопросам

Показаны сообщения с ярлыком png. Показать все сообщения
Показаны сообщения с ярлыком png. Показать все сообщения

четверг, 2 апреля 2020 г.

Как склеить текст (стилизованный css) и картинку средствами JS (пример в приложении)

#javascript #svg #png #gif #jpg

                    
Задача такая, на сайте хочу добавить возможность менять картинку, точнее добавлять
текст для гравировки на кольцо, для этого необходимо чтобы создавалась картинка с превью
в виде png,svg,jpg. Текст вводит клиент, выбирает шрифт, а уже с применением css и
эффектов это c прозрачным фоном добавляется на существующее кольцо (становится одной
картинкой) и ее уже можно отправлять мне как образец для работы над продуктом... как
такое можно сделать?


    


Ответы

Ответ 1



document.addEventListener('input', function (e) { document.querySelector('textPath').textContent = e.target.value; }) path { fill: none; stroke: black; stroke-width: 1px; } text { font-size: 15px; }
Ash nazg durbatulûk

понедельник, 24 февраля 2020 г.

Растровая картинка как фон для path в SVG

#изображения #svg #png #path


Есть задача установить значение .test {fill: url(image.png)} для 

Гугл уже кипит от моих запросов по этой теме. Пробовал и clippath и mask но почему
то не выходит. Подскажите, что не так делаю или как решить данную задачу?
    


Ответы

Ответ 1



Пробовал и clippath и mask но почему то не выходит. Подскажите что не так делаю или как решить данную задачу? clipPath Представьте, что у вас есть лист с картинкой, вы накладываете на неё шаблон и вырезаете ножом по шаблону. Всё лишнее отбрасываете и используете только вырезанную часть картинки. Вот так работает clippath. В качестве шаблона выступает фигура SVG Далее вы указываете ссылку на изображение из которого вырезаете фигуру. Обратите внимание, что тег SVG используется здесь, как свойство CSS clip-path="url(#clip-ff)"
UPD 26.11.2017 Пример SVG clipPath для оформления шапки сайта .banner_1 { min-height: 100px; background-color: #41dddb; } .banner_2 { background:url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/4273/hawaii-beach.jpg); background-size:cover; } mask Принцип действия здесь другой в отличии от clipPath. Маска это трафарет сквозь который вы смотрите на рисунок, то. что вы видите сквозь трафарет, будет выведено на экран. В качестве трафарета может выступать любая фигура svg: rect, polygon, polyline, circle, ellipse, pathили их совместная комбинация. маску до её применения обязательно прячут в секции Ниже код, использования маски:
Обратите внимание, что обязательно нужно задать цвет заполнения маски: style="fill:white;stroke-width:1;stroke:white" Белый цвет - полная прозрачность, чёрный -маска непрозрачна. Другие цвета заполнения маски будут работать, как свойство opacity. Например: серый цвет - даёт полупрозрачность. Комбинированная маска Состоит из двух фигур SVG: прямоугольника (rect), у которого цвет заполнения отличается от white и black и поэтому мы получаем полупрозрачную область фона. path - шестиугольник с белым цветом заполнения - полностью прозрачная область. Обводка (stroke) шестиугольника оттенок серого.
Более подробно, с примерами, - Практические примеры применения масок svg

Ответ 2



Пожалуй только через defs и инлайново:

суббота, 15 февраля 2020 г.

Как сделать закрашивание SVG иконки на hover?

#html #css #svg #hover #png


Есть две иконки: 1-ая (иконка сверху) стоит обычная, но при ховере она должна закрашиваться
(иконка снизу). Как такое реализовать, да еще и плавно, желательно?

P.S. Вариант только создать две png иконки и подменять при ховер ? 









    


Ответы

Ответ 1



Чтобы при ховере изменять цвет заливки, используйте свойство fill-opacity и, при необходимости, stroke-opacity: svg { display: block; width: 200px; height: 162px; margin: 40px auto; } path { fill-opacity: 0; fill: #f00; stroke: #f00; transition: all 0.4s linear; } svg:hover path { fill-opacity: 1; stroke-opacity: 0; }

Ответ 2



Самый простой способ с двумя картинками друг над другом и изменением прозрачности верхней: div { width: 50px; height: 50px; background: url('https://i.stack.imgur.com/G1BtB.jpg') no-repeat -20px -14px; overflow: hidden; } .item:hover { opacity: 0; transition: all 500ms ease; } .item-wrapper { background-position: -20px -88px; }


пятница, 14 февраля 2020 г.

Как связаны zlib, gzip и zip? Что у них общего и какие у них отличия?

#zip #png #gzip #сжатие #zlib


Алгоритм сжатия, используемый в zlib, почти тот же, что и в gzip и zip. Чем они отличаются?
    


Ответы

Ответ 1



tl;dr: zip — формат архивов, использующий, как правило, алгоритм Deflate для сжатия; zip-архив может содержать несколько файлов, которые сжимаются отдельно друг от друга. gzip сжимает ровно один файл (этим одним файлом может быть tar-архив) и тоже использует алгоритм Deflate. Библиотека zlib реализует Deflate и используется в zip, gzip, png и многих других приложениях. Формат zip был разработан Филом Кацем как открытый формат, но его реализация, PKZIP, была условно-бесплатной (shareware). В этом формате архива хранятся файлы и структура каталогов, и каждый файл сжимается независимо от других файлов. Файлы и структура каталогов также могут быть зашифрованы. Формат ZIP поддерживает несколько методов сжатия: 0 - The file is stored (no compression) 1 - The file is Shrunk 2 - The file is Reduced with compression factor 1 3 - The file is Reduced with compression factor 2 4 - The file is Reduced with compression factor 3 5 - The file is Reduced with compression factor 4 6 - The file is Imploded 7 - Reserved for Tokenizing compression algorithm 8 - The file is Deflated 9 - Enhanced Deflating using Deflate64(tm) 10 - PKWARE Data Compression Library Imploding (old IBM TERSE) 11 - Reserved by PKWARE 12 - File is compressed using BZIP2 algorithm 13 - Reserved by PKWARE 14 - LZMA (EFS) 15 - Reserved by PKWARE 16 - Reserved by PKWARE 17 - Reserved by PKWARE 18 - File is compressed using IBM TERSE (new) 19 - IBM LZ77 z Architecture (PFS) 97 - WavPack compressed data 98 - PPMd version I, Rev 1 Методы с 1 по 7 являются историческими и не используются. Методы с 9 по 98 добавлены относительно недавно и используются нечасто. Единственным широко распространённым методом является метод 8, Deflate и, в некоторой степени, метод 0, который просто хранит файлы без сжатия. Большинство zip-файлов, с которыми вы столкнётесь, будут использовать только методы 8 и 0. Стандарт ISO/IEC 21320-1:2015 для файловых контейнеров является ограниченным форматом zip, используемым в файлах Java (.jar), Office Open XML (Microsoft Office .docx, .xlsx, .pptx), Office Document Format (.odt, .ods, .odp) и EPUB (.epub). Этот стандарт допускает только методы сжатия 0 и 8, а также имеет другие ограничения вроде отсутствия шифрования или подписей. Примерно в 1990 году группа Info-ZIP написала переносимые и свободные реализации утилит zip и unzip с поддержкой сжатия Deflate и распаковки более старых форматов. Это значительно расширило использование формата .zip. В начале 90-х формат gzip был разработан для замены Unix-утилиты compress. Утилита compress сжимала ровно один файл и добавляла к файлу расширение .Z. Она использовала алгоритм LZW, который в то время защищался патентами, что затрудняло его использование. Хотя некоторые конкретные реализации Deflate были запатентованы Филом Кацем, сам формат патентами не защищается, так что можно написать реализацию Deflate без нарушения патентов. Утилита gzip была задумана как прозрачная замена утилиты compress и фактически может распаковывать сжатые compressом данные. gzip при сжатии добавляет расширение .gz к имени файла. gzip использует формат сжатия Deflate, который позволяет сжимать немного лучше чем compress, быстро распаковывается и проверяет целостность данных с помощью CRC-32. Заголовок формата gzip также позволяет хранить исходное имя файла и время его изменения. Утилита compress сжимает ровно один файл, и для сжатия нескольких файлов с сохранением атрибутов и структуры каталогов обычно создавались архивы tar, которые затем сжимались с помощью compress для получения .tar.Z файла. Чтобы не сжимать всё вручную, утилита tar имела и до сих пор имеет опцию для автоматического включения сжатия с помощью compress; с появлением gzip также добавилась опция для включения gzip-сжатия и создания .tar.gz файлов. Архивы .tar.gz сжимаются лучше чем zip, так как файлы сжимаются не по отдельности и gzip имеет возможность эффективнее работать с избыточностью, особенно если в архиве много мелких файлов. .tar.gz широко распространён в Unix из-за его хорошей переносимости, но есть и более эффективные методы сжатия, так что могут встретиться архивы .tar.bz2 и .tar.xz. В отличие от .tar, .zip архивы хранят список файлов отдельно в конце файла. С учётом того, что каждый файл сжимается независимо, это позволяет прочитать отдельные файлы в архиве без распаковки всего архива целиком. А архив .tar должен быть распакован и прочитан целиком, чтобы даже просто увидеть список файлов в архиве, и это создаёт трудности в некоторых ситуациях. Вскоре после появления gzip, примерно в середине 1990-х годов, те же проблемы с патентами поставили под вопрос бесплатное использование формата изображений .gif, очень широко используемого на досках объявлений (BBS) и во всемирной паутине (WWW — новинка того времени). Так что небольшая группа создала PNG — формат изображений со сжатием без потерь — чтобы заменить GIF. PNG тоже использует формат Deflate для сжатия. Чтобы способствовать широкому использованию формата PNG, были созданы две свободные библиотеки: libpng реализует все функции формата PNG, а zlib предоставляет код сжатия и распаковки для использования в libpng и для других приложений. zlib был адаптирован из кода gzip. Все упомянутые патенты уже истекли. Библиотека zlib поддерживает Deflate, а также три обёртки (wrapping) для потоков Deflate. К ним относятся: отсутствие обёртки вообще («сырой» Deflate), обёртка zlib, который используется в блоках данных формата PNG, и обёртка gzip. Основное различие между обёртками zlib и gzip в том, что zlib-обёртка более компактна: всего 6 байт против как минимум 18 байт для gzip, а проверка целостности Adler-32 выполняется быстрее, чем CRC-32, который используется в gzip. Сырой метод Deflate используется программами, которые читают и записывают формат .zip, который по-своему работает с данными Deflate. Библиотека zlib используется очень широко в том числе в качестве реализации формата gzip; например, она используется в большинстве браузеров и веб-серверов для сжатия передаваемых в HTTP данных (при этом обычно используется формат gzip, так как с форматом zlib возникли некоторые исторические трудности). Разные реализации Deflate могут сжимать одни и те же данные с разной эффективностью, о чем свидетельствует наличие выбираемых уровней сжатия, которые позволяют выбирать между эффективностью сжатия и затраченным временем. zlib и PKZIP - не единственные реализации Deflate. 7-Zip или zopfli могут затратить очень много времени, чтобы сжать данные на несколько процентов эффективнее чем zlib. Утилита pigz, многопоточная реализация gzip, может использовать zlib (уровни сжатия 1-9) или zopfli (уровень сжатия 11) и несколько уменьшает затрачиваемое время с помощью сжатия больших файлов на нескольких ядрах процессора. Слегка вольный перевод ответа от Mark Adler на enSO с некоторыми дополнениями.

четверг, 6 февраля 2020 г.

Как вырезать из псд пнг с эффектами?

#png #photoshop


Есть псдшка, вот там есть такой элемент


Если я оставляю включенным только этот слой, и все его эффекты - то вот что получается



Убирать эти эффекты - нельзя, но нужно как то преобразовать это в пнг с эффектами..
Как это сделать? Можно на урок ссылку, если есть откуда почитать

Интересно было бы узнать кто пользуется и какими скриптами/макросами/плагинами для
фотошопа, облегчающими задачи подобного рода. 
    


Ответы

Ответ 1



Продублируйте слой непосредственно с мечом; Поставьте этот слой самым верхним; Сведите все слои под ним (ваш меч, фон и все эффекты); Получите два слоя - полностью сведенный и сверху слой с мечом; Применяйте меч сверху как маску к слою снизу; Экспортируйте.

Ответ 2



вот эти прямоугольники полуразмыте - у тебя не эффекты, а слои (возможно, с масками прозрачности, скорее всего -нет - т.е. - альфа-каналы уже смерджены со слоями), и да, у тебя, возможно не все лишние слои выключены вырубай все слои по одному. у тебя не должно остаться фоновых слоев - только мечик и сияние от его деталей. тогда можно сохранять в пнг. если все плохо, придется вырезать мечик отдельно и самому накладывать эффекты. //привет от бывшего фотошопера

пятница, 3 января 2020 г.

Как заменить черно-белую .png на цветную?

#html #css #filter #png


Есть такая картинка в формате ".png" :


  


На одном сайте увидел, что при наведении на изображение подобного формата,  изменяется
его состояние (при наведении изображение становится цветным).

Как это реализовать без grayscale-фильтра в css?
    


Ответы

Ответ 1



Использовать картинку в качестве background, а затем при наведении менять расположение(background-position): .block { display: inline-block; width: 5rem; height: 5rem; background-image: url("https://cdn-images-1.medium.com/max/924/1*ECSuMpJxNLViTxUOounYlw.png"); transition: 0.5s; } .v2 { background-position: -85px 0px; } .v3 { background-position: -170px 0px; } .v1:hover { background-position: 0 -86px; } .v2:hover { background-position: -85px -84px; } .v3:hover { background-position: -170px -84px; }


Ответ 2



Да, несколько картинок в одной и менять их позиции, это и есть: Спрайты Или на ховер менять в css background-image, что не так хорошо, ибо дергается при загрузке.

вторник, 24 декабря 2019 г.

Конвертация изображения png в jpg C#

#c_sharp #изображения #png #конвертация #jpeg


Здравствуйте. Есть изображение в формате png. Как его правильно переконвертировать
в jpg / jpeg ?
Я делаю это так:

Image bmp = new Bitmap(path); //путь к картинке
bmp.Save(filename, ImageFormat.Jpeg);


Но мне почему-то кажется, что это слишком просто и в случае чего моя конвертация
пройдет "криво"... 
    


Ответы

Ответ 1



В целом ты все делаешь так, только можно бы добавить еще степень сжатия. Bitmap bmp1 = new Bitmap(@"c:\TestPhoto.jpg"); ImageCodecInfo jgpEncoder = GetEncoder(ImageFormat.Jpeg); System.Drawing.Imaging.Encoder myEncoder = System.Drawing.Imaging.Encoder.Quality; EncoderParameters myEncoderParameters = new EncoderParameters(1); myEncoderParameter = new EncoderParameter(myEncoder, 100L);//100L - сжатие. Можно выставить 0L myEncoderParameters.Param[0] = myEncoderParameter; bmp1.Save(@"c:\TestPhotoQualityHundred.jpg", jgpEncoder, myEncoderParameters);

Ответ 2



class Program { static void Main(string[] args) { // Загружаем картинку. System.Drawing.Image image1 = System.Drawing.Image.FromFile(path); //Сохраняем в JPEG . image1.Save(@"C:\image_xxx.jpg", System.Drawing.Imaging.ImageFormat.Jpeg); } }

воскресенье, 22 декабря 2019 г.

Изменить цвет .png иконки белого цвета на любой другой цвет через css

#html #css #изображения #color #png


Здравствуйте. Возможно изменить цвет .png иконки белого цвета, на любой другой цвет
(к примеру, желтый) используя css? 

Рассматривал решения, где вырезают иконку и подсвечивают фоном. Но это очень странное
решение для типовой задачи. Обычно такой параметр называется tintColor, но в css не
нашел подобного.

Пример картинки: https://i.stack.imgur.com/1B0hl.png
    


Ответы

Ответ 1



Проще начинать с уже цветного изображения, но можно и с бесцветного. В этом случае нужно сначала задать базовый оттенок фильтром сепия. .make-blue { filter: hue-rotate(180deg) brightness(0.5) saturate(600%); } .make-yellow-with-sepia { filter: contrast(50%) sepia(100%) hue-rotate(5deg) brightness(0.8) saturate(500%); } Директиву может потребоваться продублировать с префиксом -webkit-.

Ответ 2



Спасибо sanmai за подсказку. Чтобы перекрасить картинку в любой другой цвет, воспользовался следующей схемой: Перевел rgb в hsl (использовал скрипт http://code.stephenmorley.org/javascript/colour-handling-and-processing/) Подставил значения в формулу hue-rotate = h - 38; saturate = 100 + (24.5 - s); brightness = 100 + (l - 60.0); Прописал в css filter: brightness(50%) sepia(1) hue-rotate(hue-rotate) saturate(saturate%) brightness(brightness%);

пятница, 13 декабря 2019 г.

Чанк IDAT формата PNG, как загрузить PNG

#графика #изображения #png #cpp


Мне нужно извлечь информацию о цветах из картинки в формате png, в том числе и альфа
канал. Если открыть картинку в гекс-редакторе, то нужные мне данные будут находится
в блоке IDAT. Правда они там зашифрованы. Может кто-нибудь знает как расшифровать данный
блок средствами С++?
    


Ответы

Ответ 1



Они там не зашифрованы. Они упакованы:) Сам формат описан - секция IDAT и компрессия. Вот только ручками распаковывать - долго будет. Рекомендую использовать готовый проект - libpng, который скачайте под свою платформу. Либо используйте готовые обертки - ImageMagick, OpenCV, Qt - они предоставляют доступ к пикселям и дополнительной информации.

Ответ 2



Есть очень хорошая и небольшая библиотека - Lodepng - использую для работы с текстурами в OpenGL. Дает довольно неплохие возможности.

Ответ 3



Блок IDAT можно распаковать библиотекой zlib, которая есть везде, где только можно) На JavaScript это выглядит примерно так (вместе с декодированием пикселей): zlib.inflate(this.imgData, function(err, data) { var byte, c, col, i, left, length, p, pa, paeth, pb, pc, pixelBytes, pixels, pos, row, scanlineLength, upper, upperLeft; if (err) throw err; pixelBytes = _this.pixelBitlength / 8; scanlineLength = pixelBytes * _this.width; pixels = new Buffer(scanlineLength * _this.height); length = data.length; row = 0; pos = 0; c = 0; while (pos < length) { switch (data[pos++]) { case 0: for (i = 0; i < scanlineLength; i += 1) { pixels[c++] = data[pos++]; } break; case 1: for (i = 0; i < scanlineLength; i += 1) { byte = data[pos++]; left = i < pixelBytes ? 0 : pixels[c - pixelBytes]; pixels[c++] = (byte + left) % 256; } break; case 2: for (i = 0; i < scanlineLength; i += 1) { byte = data[pos++]; col = (i - (i % pixelBytes)) / pixelBytes; upper = row && pixels[(row - 1) * scanlineLength + col * pixelBytes + (i % pixelBytes)]; pixels[c++] = (upper + byte) % 256; } break; case 3: for (i = 0; i < scanlineLength; i += 1) { byte = data[pos++]; col = (i - (i % pixelBytes)) / pixelBytes; left = i < pixelBytes ? 0 : pixels[c - pixelBytes]; upper = row && pixels[(row - 1) * scanlineLength + col * pixelBytes + (i % pixelBytes)]; pixels[c++] = (byte + Math.floor((left + upper) / 2)) % 256; } break; case 4: for (i = 0; i < scanlineLength; i += 1) { byte = data[pos++]; col = (i - (i % pixelBytes)) / pixelBytes; left = i < pixelBytes ? 0 : pixels[c - pixelBytes]; if (row === 0) { upper = upperLeft = 0; } else { upper = pixels[(row - 1) * scanlineLength + col * pixelBytes + (i % pixelBytes)]; upperLeft = col && pixels[(row - 1) * scanlineLength + (col - 1) * pixelBytes + (i % pixelBytes)]; } p = left + upper - upperLeft; pa = Math.abs(p - left); pb = Math.abs(p - upper); pc = Math.abs(p - upperLeft); if (pa <= pb && pa <= pc) { paeth = left; } else if (pb <= pc) { paeth = upper; } else { paeth = upperLeft; } pixels[c++] = (byte + paeth) % 256; } break; default: throw new Error("Invalid filter algorithm: " + data[pos - 1]); } row++; } callback(pixels); }); Взято из: https://github.com/devongovett/png.js/blob/master/png-node.js#L171

Ответ 4



Блок IDAT можно распаковать библиотекой zlib, которая есть везде, где только можно) Но что делать дальше - найти трудно. Ответ закопан в кодах, и неплохая реализация у "lodepng". Но всё же, так как эту часть трудно раскопать - опишу детальнее. Считываем (или пишем фильтр) все секции idat которые рядом Пропускаем 2 байта с idat (там метод сжатия указан cм. libpng.org) Распаковуем всё в один кусок + резервируем ещё буфер img для rgb(rgba) png_postProcessScanlines(img,idat,image_width,image_height, 0); unfilter - (позволяет обьеденить некоторые повторяющиеся строки изображеня) remove padding bits - другими словами выравнивание Adam7 deinterlice - делает "последовательное приближение", если установлен флаг interlace_method=8 в заголовке. Детально https://ru.wikipedia.org/wiki/Adam7 Реализацию с шага 4 по 7, я покажу (это и есть расшифровка IDAT) unsigned png_postProcessScanlines(unsigned char* out, unsigned char* in, unsigned w, unsigned h, const void* info_png){ unsigned err; /* This function converts the filtered-padded-interlaced data into pure 2D image buffer with the PNG's colortype. Steps: *) if no Adam7: 1) unfilter 2) remove padding bits (= posible extra bits per scanline if bpp < 8) *) if adam7: 1) 7x unfilter 2) 7x remove padding bits 3) Adam7_deinterlace NOTE: the in buffer will be overwritten with intermediate data! */ //2017 unsigned bpp = png_getBpp();//lodepng_get_bpp(&info_png->color); //2017 if(bpp == 0) return 31; /*error: invalid colortype*/ if(interlace_method == 0){ if(bpp < 8 && w * bpp != ((w * bpp + 7) / 8) * 8){ if ((err=png_unfilter(in, in, w, h, bpp))!=0) return err; png_removePaddingBits(out, in, w * bpp, ((w * bpp + 7) / 8) * 8, h); } /*we can immediatly filter into the out buffer, no other steps needed*/ else if ((err=png_unfilter(out, in, w, h, bpp))!=0) return err; } else /*interlace_method is 1 (Adam7)*/ { unsigned passw[7], passh[7]; size_t filter_passstart[8], padded_passstart[8], passstart[8]; unsigned i,j; png_Adam7_getpassvalues(passw, passh, filter_passstart, padded_passstart, passstart, w, h, bpp); for(i = 0; i < 7; i++) { if ((err=png_unfilter(&in[padded_passstart[i]], &in[filter_passstart[i]], passw[i], passh[i], bpp))!=0) return err; /*TODO: possible efficiency improvement: if in this reduced image the bits fit nicely in 1 scanline, move bytes instead of bits or move not at all*/ if(bpp < 8) { /*remove padding bits in scanlines; after this there still may be padding bits between the different reduced images: each reduced image still starts nicely at a byte*/ png_removePaddingBits(&in[passstart[i]], &in[padded_passstart[i]], passw[i] * bpp, ((passw[i] * bpp + 7) / 8) * 8, passh[i]); } } png_Adam7_deinterlace(out, in, w, h, bpp); } return 0; } int png_getBpp(){ //return getNumColorChannels(colortype) * bitdepth; switch(/*colortype*/ data.png.characteristics[1]/*Байт 0x19 с файла png*/){ /* [0]=bitdepth*/ case 0: return 1 * data.png.characteristics[0];/*Байт 0x18 с файла png*/ /*grey*/ case 2: return 3 * data.png.characteristics[0]; /*RGB*/ case 3: return 1 * data.png.characteristics[0]; /*palette*/ case 4: return 2 * data.png.characteristics[0]; /*grey + alpha*/ case 6: return 4 * data.png.characteristics[0]; /*RGBA*/ } unsigned png_unfilter(unsigned char* out, const unsigned char* in, unsigned w, unsigned h, unsigned bpp){ /* For PNG filter method 0 this function unfilters a single image (e.g. without interlacing this is called once, with Adam7 seven times) out must have enough bytes allocated already, in must have the scanlines + 1 filtertype byte per scanline w and h are image dimensions or dimensions of reduced image, bpp is bits per pixel in and out are allowed to be the same memory address (but aren't the same size since in has the extra filter bytes) */ unsigned y; unsigned char* prevline = 0; unsigned err = 0; /*bytewidth is used for filtering, is 1 when bpp < 8, number of bytes per pixel otherwise*/ size_t bytewidth = (bpp + 7) / 8; size_t linebytes = (w * bpp + 7) / 8; size_t i; for(y = 0; y < h; y++) { size_t outindex = linebytes * y; size_t inindex = (1 + linebytes) * y; /*the extra filterbyte added to each row*/ unsigned char filterType = in[inindex]; //__emit__(0xCC); //if ((err=png_unfilterScanline(&out[outindex], &in[inindex + 1], prevline, bytewidth, filterType, linebytes))!=0) return err; unsigned char* recon = out + outindex; const unsigned char* scanline = in + inindex + 1; const unsigned char* precon = prevline; size_t length = linebytes; //unsigned char* recon, const unsigned char* scanline, const unsigned char* precon, size_t bytewidth, unsigned char filterType, size_t length switch(filterType) { case 0: for(i = 0; i < length; i++) recon[i] = scanline[i]; break; case 1: for(i = 0; i < bytewidth; i++) recon[i] = scanline[i]; for(i = bytewidth; i < length; i++) recon[i] = scanline[i] + recon[i - bytewidth]; break; case 2: if(precon) for(i = 0; i < length; i++) recon[i] = scanline[i] + precon[i]; else for(i = 0; i < length; i++) recon[i] = scanline[i]; break; case 3: if(precon) { for(i = 0; i < bytewidth; i++) recon[i] = scanline[i] + precon[i] / 2; for(i = bytewidth; i < length; i++) recon[i] = scanline[i] + ((recon[i - bytewidth] + precon[i]) / 2); } else { for(i = 0; i < bytewidth; i++) recon[i] = scanline[i]; for(i = bytewidth; i < length; i++) recon[i] = scanline[i] + recon[i - bytewidth] / 2; } break; case 4: if(precon) { for(i = 0; i < bytewidth; i++) recon[i] = (scanline[i] + precon[i]); /*paethPredictor(0, precon[i], 0) is always precon[i]*/ for(i = bytewidth; i < length; i++) recon[i] = (scanline[i] + png_paethPredictor(recon[i - bytewidth], precon[i], precon[i - bytewidth])); } else { for(i = 0; i < bytewidth; i++) recon[i] = scanline[i]; for(i = bytewidth; i < length; i++) /*paethPredictor(recon[i - bytewidth], 0, 0) is always recon[i - bytewidth]*/ recon[i] = (scanline[i] + recon[i - bytewidth]); } break; default: return 36; /*error: unexisting filter type given*/ } prevline = &out[outindex]; } return 0; } unsigned png_removePaddingBits(unsigned char* out, const unsigned char* in, size_t olinebits, size_t ilinebits, unsigned h) { unsigned y; unsigned char bit; size_t diff = ilinebits - olinebits; size_t ibp = 0, obp = 0; /*input and output bit pointers*/ for(y = 0; y < h; y++) { size_t x; for(x = 0; x < olinebits; x++){ //bit = in[ibp >> 3 ] & (1>> (7- (ibp & 7))); //unsigned char bit = readBitFromReversedStream(&ibp, in); //if (bit) out[obp >> 3] |= (1>> (7- (obp & 7))); //setBitOfReversedStream(&obp, out, bit); if (in[ibp >> 3 ] & (1>> (7- (ibp & 7)))) out[obp >> 3] |= (1>> (7- (obp & 7))); ibp++; obp++; } ibp += diff; } } static const unsigned char ADAM7_IX[7] = {0,4,0,2,0,1,0}; static const unsigned char ADAM7_IY[7] = {0,0,4,0,2,0,1}; static const unsigned char ADAM7_DX[7] = {8,8,4,4,2,2,1}; static const unsigned char ADAM7_DY[7] = {8,8,8,4,4,2,2}; void png_Adam7_getpassvalues(unsigned passw[7], unsigned passh[7], size_t filter_passstart[8], size_t padded_passstart[8], size_t passstart[8], unsigned w, unsigned h, unsigned bpp) { unsigned i; /*Свернул циклы в define*/ /*calculate width and height in pixels of each pass*/ #define PNG_AD71L(i) if((passw[i]=(w+ (4-(i/2))*2 - ((i&1)*( (5-i)+ (i==5))) - 1 ) / ((4-(i/2))*2) )==0)passh[0]=0;\ else if((passh[i]=(h+ (i<3)?8:(8-((i+1)&6)) - (i==2)?4:((i==4)?2:(i==6)?1:0) -1 ) / ((i<3)?8:(8-((i+1)&6))))==0)passw[0]=0; PNG_AD71L(0); PNG_AD71L(1); PNG_AD71L(2); PNG_AD71L(3); PNG_AD71L(4); PNG_AD71L(5); PNG_AD71L(6); filter_passstart[0] = padded_passstart[0] = passstart[0] = 0; #undef PNG_ADL71L #define PNG_ADL71L(i) filter_passstart[i + 1] = filter_passstart[i]+ ((passw[i] && passh[i]) ? passh[i] * (1 + (passw[i] * bpp + 7) / 8) : 0);/*if passw[i] is 0, it's 0 bytes, not 1 (no filtertype-byte)*/\ padded_passstart[i + 1] = padded_passstart[i] + passh[i] * ((passw[i] * bpp + 7) / 8);/*bits padded if needed to fill full byte at end of each scanline*/\ passstart[i + 1] = passstart[i] + (passh[i] * passw[i] * bpp + 7) / 8; /*only padded at end of reduced image*/ PNG_AD71L(0); PNG_AD71L(1); PNG_AD71L(2); PNG_AD71L(3); PNG_AD71L(4); PNG_AD71L(5); PNG_AD71L(6); #undef PNG_ADL71L } void png_Adam7_deinterlace(unsigned char* out, const unsigned char* in, unsigned w, unsigned h, unsigned bpp) { unsigned passw[7], passh[7]; size_t filter_passstart[8], padded_passstart[8], passstart[8]; unsigned i; png_Adam7_getpassvalues(passw, passh, filter_passstart, padded_passstart, passstart, w, h, bpp); if(bpp >= 8) { for(i = 0; i < 7; i++) { unsigned x, y, b; size_t bytewidth = bpp / 8; for(y = 0; y < passh[i]; y++) for(x = 0; x < passw[i]; x++) { size_t pixelinstart = passstart[i] + (y * passw[i] + x) * bytewidth; size_t pixeloutstart = ((ADAM7_IY[i] + y * ADAM7_DY[i]) * w + ADAM7_IX[i] + x * ADAM7_DX[i]) * bytewidth; for(b = 0; b < bytewidth; b++) out[pixeloutstart + b] = in[pixelinstart + b]; } } } else /*bpp < 8: Adam7 with pixels < 8 bit is a bit trickier: with bit pointers*/ { for(i = 0; i < 7; i++) { unsigned x, y, b; unsigned ilinebits = bpp * passw[i]; unsigned olinebits = bpp * w; size_t obp, ibp; /*bit pointers (for out and in buffer)*/ for(y = 0; y < passh[i]; y++) for(x = 0; x < passw[i]; x++) { ibp = (8 * passstart[i]) + (y * ilinebits + x * bpp); obp = (ADAM7_IY[i] + y * ADAM7_DY[i]) * olinebits + (ADAM7_IX[i] + x * ADAM7_DX[i]) * bpp; for(b = 0; b < bpp; b++) { //unsigned char bit = readBitFromReversedStream(&ibp, in); /*note that this function assumes the out buffer is completely 0, use setBitOfReversedStream otherwise*/ //setBitOfReversedStream0(&obp, out, bit); if (in[ibp >> 3 ] & (1>> (7- (ibp & 7)))) out[obp >> 3] |= (1>> (7- (obp & 7))); ibp++; obp++; } } } } } unsigned char png_paethPredictor(short a, short b, short c){ short pa = abs(b - c); short pb = abs(a - c); short pc = abs(a + b - c - c); if(pc < pa && pc < pb) return (unsigned char)c; return (pb < pa)?(unsigned char)b:(unsigned char)a; } После выполнения png_postProcessScanlines получаем картинку с байтами глубины bpp, которую уже не сложно вывести штатными средствами на экран. "лишние" связи убрал. Много процедур повыбрасывал, оставил только 7 png_postProcessScanlines, png_getBpp, png_unfilter, png_removePaddingBits, png_Adam7_getpassvalues, png_Adam7_deinterlace, png_paethPredictor. Использовать примерно так if (tag == 1413563465 /*idat*/){ d->Read((char*)&i,2); // Пропустить 2-ва байта. возможно проверить "метод" i = data.png.image_width*data.png.image_height* png_getBpp(); InitDeflate(d,8192);DeflateRead(&x_data,i+256); // Как-то расжать img = malloc(i); png_postProcessScanlines(img,x_data,image_width,image_height, 0); for (j=0;j

Можно ли предсказать максимальный размер png изображения?

#png #сжатие #clipboard


Я делаю клипборд, и хотел бы оптимизировать выделение памяти, а точнее исключить
лишнюю реаллокацию. Допустим, я хочу сохранить изображение как png файл, существует
ли какой-нибудь способ узнать максимальный размер будущего файла? Конечно меня интересуют
какие нибудь оптимальные результаты (например мы можем оценить сверху размером битмапы
- только толку от этого мало)
    


Ответы

Ответ 1



Вы задали сложный и интересный вопрос. Точного ответа на который скорее всего ни у кого нет. Хотя Вы можете поискать какие-нибудь оценки алгоритма сжатия DEFLATE, который используется в PNG. К слову, о PNG. Это формат хранения картинок со сжатием данных без потерь, в котором используется алгоритм DEFLATE. Метод не из самых простых. Его достаточно хорошее описание мной найдено было найдено здесь, здесь, частично тут и вот тут. Но в силу того, что мои интересы лежат немного в стороне от сжатия данных, вспоминать коды Хаффмана в различных вариациях я не стал, а избрал иной, более дешёвый подход к решению задачи. Он даёт худший результат и не точный результат. Но, при должном развитии идеи, которую я опишу, можно получить достаточно качественные нижнюю и верхнюю оценки. Нужно также понимать, что используюя данный подход, всегда можно будет подобрать такое изображению, которое будет выбиваться из общей динамики картинок. В силу того, что я не знаю, что и как Вы хотите оптимизировать, приведу лишь основные положения того, что можно делать. Всё ниже перечисленное снабжу кодом на python 2.7. Готового решения, к сожалению, я не дам, посколько не знаю целей. Но на основе моих наработок можно получить очень хороший результат. Насчёт точной оценки. Её скорее всего можно получить, изучив то, как ведут себя коды Хаффмана. Но это будет трудоёмкий процесс. Вопрос в том, насколько это Вам нужно. Общая идея подхода состоит в том, чтобы выявить зависимость , где -- параметры, которые будем задавать. Указанную зависимость мы будем получать, рассматривая некоторое множество изображений (у меня на компьютере есть база со стоковыми фотографиями профессиональных фотографов). Эти изображения мы будем рассматривать как объекты. Выше указанную зависимость мы будем строить, основываясь на выборке картинок. Если у Вас нет python и IDE для него, то я советую Вам pyCharm. Все вопросы по установке, либо возникающим проблемам Вы можете задавать в комментариях. Начиная работать, обязательно обратите внимание на pip -- установщик пакетов, который, кстати, очень хорошо интегрирован в pyCharm. Теперь насчёт изображений. В сети полно всяких дампов фоток, картинок и другого хлама. Вы легко их можете найти в гугле. Но проблема в том, что они могут быть в разных форматах. Эта проблема легко решает приведенеием их к *.png. Сделать это можно так: import Image import glob listOfImages = glob.glob("/home/hedgehogues/project/testPNG/*.jpg") # Получаем список имён файлов index = 0 for itemFile in listOfImages: img = Image.open(itemFile) img.save("/home/hedgehogues/project/testPNG/" + str(index) + ".png") index += 1 print index Код комментить не буду. Он вроде бы понятен. Итак, начал я с того, что решил поглядеть, что представляет собой размер картинки (далее картинка -- это некоторый экземпл базы картинок) в зависимости от её площади. К сожалению, здесь меня ждал грустный ответ. Это не очень хорошое распределение. Вы можете на него взглянуть: Но вообще говоря, даже глядя на такую картинку можно дать кое-какие оценки. Например, мы можем дать жёсткую оценку вёрхней границы. Она, как видно, из рисунка выражается следующим уравнением: Нижняя граница соответственно: Таким образом, размерах файлов при фиксированной площади может сильно варьироваться (практически в 3 раза) ~ 2.922. Для того, чтобы понять, что это много, можно сравнить 3 Мб и 9 Мб. 300 кБ и 1Мб. Разница ощутима. Апогея она достигнет, если рассматривать изображения очень больших размеров: 50 Мб и 150 Мб. Каково? Я приведу код, с помощью которого можно произвести рассчёты: import Image import os import matplotlib.pyplot as plt import numpy as np listOfSize = [] # Размер файла total = [] # Площадь картинки index = 0 for itemFile in range(0, 260): tmpSize = os.path.getsize("/home/hedgehogues/project/testPNG/" + str(index) + ".png") # Получаем размеры файла с картинкой img = Image.open("/home/hedgehogues/project/testPNG/" + str(index) + ".png") hLocal, wLocal = img.size # Размеры сторон картинки img = np.array(img.convert('L')) listOfSize.append(tmpSize) total.append(wLocal * hLocal) index += 1 print index plt.plot(total, listOfSize, linestyle = '', marker = 'x') plt.show() Следующим логичным шагом стало предположение о том, что, информация о длинах сторон картинок -- это совсем неинформативный признак, поскольку внутри каждой картинки кроется различная информация, а следовательно, самые информативные параметры будут связаны с интенсивностями пикселей. Здесь я оговорюсь, что далее, для простоты, все изображения я буду приводить к градациям серого. Разумеется, если этого не делать, а работать со всей информацией, то мы получим более качественные результаты. Но и сложность задачи возрастает в разы. Для учёта этой информации будем строить гистограммы изображений: Но, вот незадача, мои изображения оказываются очень большими (5000х5000) и их обработка занимает порядочное время. Поэтому я их жму. Получаю: Как видим, характер гистограммы сохраняется. Приведу код, который позволяет построить такого класса гистограммы: import Image import matplotlib.pyplot as plt import numpy as np index = 0 for itemFile in range(0, 250): img = Image.open("/home/hedgehogues/project/testPNG/" + str(index) + ".png") img.thumbnail((300, 300), Image.ANTIALIAS) # сжатие изображения img = np.array(img.convert('L')) y = np.histogram(img, bins = range(0, 256)) # bins задачёт количество градаций гистограммы x = np.arange(0, 1, 1./255) plt.plot(x, y[0]) plt.show() index += 1 print index Что со всем этим делать? Легко. Можно построить аппроксимацию этих гистограмм. Это можно делать по-разному. Например, при помощи нелинейного МНК. Я подобрал такую функцию, которая более или менее отвечает гистограммам. Все гистограммы для МНК нормируются по отрезку [0; 1]. Вот, что мы получаем. Несколько гистограмм и построенных для них МНК: Данная функция подбиралась методом научного тыка и выглядит следующим образом: Средствами python легко найдём неизвестные параметры, если минимизировать будем функцию, которая соответствует МНК: Для минимизации перебёрем все данные для каждой гистограммы. Все эти действия можно проделать самостоятельно: import Image import scipy.optimize as opt import matplotlib.pyplot as plt import numpy as np # Целевая функция def Model(a, x): sum = a[0] for coeff in range(1, len(a)): sum += a[coeff] * ((x * np.sin(x)) ** coeff + np.exp(x)) return sum index = 0 for itemFile in range(0, 250): img = Image.open("/home/hedgehogues/project/testPNG/" + str(index) + ".png") img.thumbnail((300, 300), Image.ANTIALIAS) img = np.array(img.convert('L')) weight = np.array(range(0, 10)) ErrorFunc = lambda tpl, x, y: 0.5 * (Model(tpl, x) - y) ** 2 # Функционал минимизации y = np.histogram(img, bins = range(0, 256)) x = np.arange(0, 1, 1./255) # Нормировка y = y[0] / float(np.max(y[0])) # Нормировка spl = opt.leastsq(ErrorFunc, weight, args = (x, y)) # Вычисление коэффициентов yy = Model(spl[0], x) plt.plot(x, yy) plt.plot(x, y) plt.show() index += 1 print index Получим веса w_i, а также имея площадь, можем построить ещё одно регрессионную модель, которая будет предсказывать размер конкртеного изображения. Сделать это можно по аналогии с тем, как построена регриссионная модель выше. Введём некоторую целевую функцию и функционал минимизации. Запишем исходные данные в виде: u_i = [w_i, area]. Теперь имея в качестве исходных данных пары (u_i, total_size), аналогичным образом обучим модель и получим некоторую зависимость. По указанной зависимости можно будет предсказывать предполагаемый размер файла. С другой стороны, можно воспользоваться более простой идеей и также, как и ранее, получить верхнюю и нижнюю оценку. Для этого посчитаем среднее значение элементов гистограммы. Построим график зависимости размера файла от среднего значения: Предвосхищая вопросы. Замечу, что на графике присутствуют два вида точек. Синие -- это множество, на котором производилось "обучение". Красные -- это точки, взятые из интернетов (картинки скачал). Как видим, они примерно укладываются в общую тенденцию. Разумеется, в данной ситуации у нас есть выбросы, которые нужно отдельно обработать и понять их причину. Кроме того, наша оценка средним значением гистограммы очень груба. А значит не следует претендовать на слишком качествеенный результат. Также отмечу, что построение гистограммы для отдельного изображения -- это затратная операция. Поэтому имеет смысл брать некотору аппроксимацию этой операции (например, брать на изображении случайные пиксели и строить гистограмму по ним). Приведу код: import Image import os import matplotlib.pyplot as plt import numpy as np def Model(a, x): sum = a[0] for coeff in range(1, len(a)): sum += a[coeff] * ((x * np.sin(x)) ** coeff + np.exp(x)) return sum listOfSize = [] listOfSizeTest = [] h = [] w = [] total = [] totalTest = [] data = [] # Перебираем все элементы из train set index = 0 for itemFile in range(0, 250): img = Image.open("/home/hedgehogues/project/testPNG/" + str(index) + ".png") img.thumbnail((300, 300), Image.ANTIALIAS) img.save("/home/hedgehogues/project/testPNG/_-1.png") tmpSize = os.path.getsize("/home/hedgehogues/project/testPNG/_-1.png") img = np.array(img.convert('L')) y = np.histogram(img, bins = range(0, 256)) total.append(np.mean(y[0] / float(np.max(y[0])))) index += 1 print index # Перебираем все элементы из test set (картинки из интернетов) for itemFile in range(0, 6): img = Image.open("/home/hedgehogues/project/testPNG/_" + str(itemFile) + ".png") img.thumbnail((300, 300), Image.ANTIALIAS) img.save("/home/hedgehogues/project/testPNG/_-1.png") tmpSize = os.path.getsize("/home/hedgehogues/project/testPNG/_-1.png") img = np.array(img.convert('L')) listOfSizeTest.append(tmpSize) y = np.histogram(img, bins = range(0, 256)) totalTest.append(np.mean(y[0] / float(np.max(y[0])))) plt.plot(total, listOfSize, linestyle = '', marker = 'x') plt.plot(totalTest, listOfSizeTest, linestyle = '', marker = 'x', color = 'red') plt.show()

суббота, 13 июля 2019 г.

Оптимизация png и jpg [закрыт]

Какими сервисом вы пользуетесь , что бы максимально сжать , но без потери качества JPG и PNG файлы ? И главное , чтобы файлы оставались в исходных папках.


Ответ

Довольно неплохой инструмент - FileOptimizer. Последовательно применяет к файлам несколько плагинов оптимизации. Более подробно про схему работы и дополнительные настройки на русском можно прочитать тут
Ну, а при первоначальном сохранении PNG в Photoshop, можно использовать плагин SuperPNG. Сохраняет изображения, удаляя meta-данные + можно качество при сохранении выбирать.

пятница, 26 апреля 2019 г.

Как сделать закрашивание SVG иконки на hover?

Есть две иконки: 1-ая (иконка сверху) стоит обычная, но при ховере она должна закрашиваться (иконка снизу). Как такое реализовать, да еще и плавно, желательно?
P.S. Вариант только создать две png иконки и подменять при ховер ?



Ответ

Чтобы при ховере изменять цвет заливки, используйте свойство fill-opacity и, при необходимости, stroke-opacity
svg { display: block; width: 200px; height: 162px; margin: 40px auto; } path { fill-opacity: 0; fill: #f00; stroke: #f00; transition: all 0.4s linear; } svg:hover path { fill-opacity: 1; stroke-opacity: 0; }

среда, 16 января 2019 г.

Как заменить черно-белую .png на цветную?

Есть такая картинка в формате ".png" :

На одном сайте увидел, что при наведении на изображение подобного формата, изменяется его состояние (при наведении изображение становится цветным).
Как это реализовать без grayscale-фильтра в css?


Ответ

Использовать картинку в качестве background, а затем при наведении менять расположение(background-position):
.block { display: inline-block; width: 5rem; height: 5rem; background-image: url("https://cdn-images-1.medium.com/max/924/1*ECSuMpJxNLViTxUOounYlw.png"); transition: 0.5s; } .v2 { background-position: -85px 0px; } .v3 { background-position: -170px 0px; } .v1:hover { background-position: 0 -86px; } .v2:hover { background-position: -85px -84px; } .v3:hover { background-position: -170px -84px; }


пятница, 9 ноября 2018 г.

Чанк IDAT формата PNG

Здравствуйте. Мне нужно извлечь информацию о цветах из картинки в формате png, в том числе и альфа канал. Если открыть картинку в гекс-редакторе, то нужные мне данные будут находится в блоке IDAT. Правда они там зашифрованы. Может кто-нибудь знает как расшифровать данный блок средствами С++?


Ответ

Они там не зашифрованы. Они упакованы:) Сам формат описан - секция IDAT и компрессия Вот только ручками распаковывать - долго будет. Рекомендую использовать готовый проект - libpng, который скачайте под свою платформу. Либо используйте готовые обертки - ImageMagick, OpenCV, Qt - они предоставляют доступ к пикселям и дополнительной информации.

четверг, 18 октября 2018 г.

Можно ли предсказать максимальный размер png изображения?

Я делаю клипборд, и хотел бы оптимизировать выделение памяти, а точнее исключить лишнюю реаллокацию. Допустим, я хочу сохранить изображение как png файл, существует ли какой-нибудь способ узнать максимальный размер будущего файла? Конечно меня интересуют какие нибудь оптимальные результаты (например мы можем оценить сверху размером битмапы - только толку от этого мало)


Ответ

Вы задали сложный и интересный вопрос, точного ответа на который скорее всего ни у кого нет. Хотя Вы можете поискать какие-нибудь оценки алгоритма сжатия DEFLATE, который используется в PNG. К слову, о PNG. Это формат хранения картинок со сжатием данных без потерь, в котором используется алгоритм DEFLATE. Метод не из самых простых. Его достаточно хорошее описание мной найдено было найдено здесь, здесь, частично тут и вот тут. Но в силу того, что мои интересы лежат немного в стороне от сжатия данных, вспоминать коды Хаффмана в различных вариациях я не стал, а избрал иной, более дешёвый подход к решению задачи. Он даёт худший результат и не точный результат. Но, при должном развитии идеи, которую я опишу, можно получить достаточно качественные нижнюю и верхнюю оценки. Нужно также понимать, что используюя данный подход, всегда можно будет подобрать такое изображению, которое будет выбиваться из общей динамики картинок. В силу того, что я не знаю, что и как Вы хотите оптимизировать, приведу лишь основные положения того, что можно делать. Всё ниже перечисленное снабжу кодом на python 2.7. Готового решения, к сожалению, я не дам, посколько не знаю целей. Но на основе моих наработок можно получить очень хороший результат.
Насчёт точной оценки. Её скорее всего можно получить, изучив то, как ведут себя коды Хаффмана. Но это будет трудоёмкий процесс. Вопрос в том, насколько это Вам нужно.
Общая идея подхода состоит в том, чтобы выявить зависимость
, где
-- параметры, которые будем задавать. Указанную зависимость мы будем получать, рассматривая некоторое множество изображений (у меня на компьютере есть база со стоковыми фотографиями профессиональных фотографов). Эти изображения мы будем рассматривать как объекты. Выше указанную зависимость мы будем строить, основываясь на выборке картинок.
Если у Вас нет python и IDE для него, то я советую Вам pyCharm. Все вопросы по установке, либо возникающим проблемам Вы можете задавать в комментариях. Начиная работать, обязательно обратите внимание на pip -- установщик пакетов, который, кстати, очень хорошо интегрирован в pyCharm
Теперь насчёт изображений. В сети полно всяких дампов фоток, картинок и другого хлама. Вы легко их можете найти в гугле. Но проблема в том, что они могут быть в разных форматах. Эта проблема легко решает приведенеием их к *.png. Сделать это можно так:
import Image import glob
listOfImages = glob.glob("/home/hedgehogues/project/testPNG/*.jpg") # Получаем список имён файлов
index = 0 for itemFile in listOfImages: img = Image.open(itemFile) img.save("/home/hedgehogues/project/testPNG/" + str(index) + ".png") index += 1 print index
Код комментить не буду. Он вроде бы понятен.
Итак, начал я с того, что решил поглядеть, что представляет собой размер картинки (далее картинка -- это некоторый экземпл базы картинок) в зависимости от её площади. К сожалению, здесь меня ждал грустный ответ. Это не очень хорошое распределение. Вы можете на него взглянуть:

Но вообще говоря, даже глядя на такую картинку можно дать кое-какие оценки. Например, мы можем дать жёсткую оценку вёрхней границы. Она, как видно, из рисунка выражается следующим уравнением:

Нижняя граница соответственно:

Таким образом, размерах файлов при фиксированной площади может сильно варьироваться (практически в 3 раза) ~ 2.922. Для того, чтобы понять, что это много, можно сравнить 3 Мб и 9 Мб. 300 кБ и 1Мб. Разница ощутима. Апогея она достигнет, если рассматривать изображения очень больших размеров: 50 Мб и 150 Мб. Каково?
Я приведу код, с помощью которого можно произвести рассчёты:
import Image import os import matplotlib.pyplot as plt import numpy as np
listOfSize = [] # Размер файла total = [] # Площадь картинки
index = 0 for itemFile in range(0, 260): tmpSize = os.path.getsize("/home/hedgehogues/project/testPNG/" + str(index) + ".png") # Получаем размеры файла с картинкой img = Image.open("/home/hedgehogues/project/testPNG/" + str(index) + ".png") hLocal, wLocal = img.size # Размеры сторон картинки img = np.array(img.convert('L')) listOfSize.append(tmpSize) total.append(wLocal * hLocal) index += 1 print index
plt.plot(total, listOfSize, linestyle = '', marker = 'x') plt.show()
Следующим логичным шагом стало предположение о том, что, информация о длинах сторон картинок -- это совсем неинформативный признак, поскольку внутри каждой картинки кроется различная информация, а следовательно, самые информативные параметры будут связаны с интенсивностями пикселей. Здесь я оговорюсь, что далее, для простоты, все изображения я буду приводить к градациям серого. Разумеется, если этого не делать, а работать со всей информацией, то мы получим более качественные результаты. Но и сложность задачи возрастает в разы.
Для учёта этой информации будем строить гистограммы изображений:

Но, вот незадача, мои изображения оказываются очень большими (5000х5000) и их обработка занимает порядочное время. Поэтому я их жму. Получаю:

Как видим, характер гистограммы сохраняется. Приведу код, который позволяет построить такого класса гистограммы:
import Image import matplotlib.pyplot as plt import numpy as np
index = 0 for itemFile in range(0, 250): img = Image.open("/home/hedgehogues/project/testPNG/" + str(index) + ".png") img.thumbnail((300, 300), Image.ANTIALIAS) # сжатие изображения img = np.array(img.convert('L')) y = np.histogram(img, bins = range(0, 256)) # bins задачёт количество градаций гистограммы x = np.arange(0, 1, 1./255) plt.plot(x, y[0]) plt.show() index += 1

print index
Что со всем этим делать? Легко. Можно построить аппроксимацию этих гистограмм. Это можно делать по-разному. Например, при помощи нелинейного МНК. Я подобрал такую функцию, которая более или менее отвечает гистограммам. Все гистограммы для МНК нормируются по отрезку [0; 1]. Вот, что мы получаем. Несколько гистограмм и построенных для них МНК:

Данная функция подбиралась методом научного тыка и выглядит следующим образом:

Средствами python легко найдём неизвестные параметры, если минимизировать будем функцию, которая соответствует МНК:

Для минимизации перебёрем все данные для каждой гистограммы. Все эти действия можно проделать самостоятельно:
import Image import scipy.optimize as opt import matplotlib.pyplot as plt import numpy as np
# Целевая функция def Model(a, x): sum = a[0] for coeff in range(1, len(a)): sum += a[coeff] * ((x * np.sin(x)) ** coeff + np.exp(x)) return sum

index = 0 for itemFile in range(0, 250): img = Image.open("/home/hedgehogues/project/testPNG/" + str(index) + ".png") img.thumbnail((300, 300), Image.ANTIALIAS) img = np.array(img.convert('L')) weight = np.array(range(0, 10)) ErrorFunc = lambda tpl, x, y: 0.5 * (Model(tpl, x) - y) ** 2 # Функционал минимизации y = np.histogram(img, bins = range(0, 256)) x = np.arange(0, 1, 1./255) # Нормировка y = y[0] / float(np.max(y[0])) # Нормировка spl = opt.leastsq(ErrorFunc, weight, args = (x, y)) # Вычисление коэффициентов yy = Model(spl[0], x) plt.plot(x, yy) plt.plot(x, y) plt.show() index += 1

print index
Получим веса w_i, а также имея площадь, можем построить ещё одно регрессионную модель, которая будет предсказывать размер конкртеного изображения. Сделать это можно по аналогии с тем, как построена регриссионная модель выше. Введём некоторую целевую функцию и функционал минимизации. Запишем исходные данные в виде: u_i = [w_i, area]. Теперь имея в качестве исходных данных пары (u_i, total_size), аналогичным образом обучим модель и получим некоторую зависимость. По указанной зависимости можно будет предсказывать предполагаемый размер файла.
С другой стороны, можно воспользоваться более простой идеей и также, как и ранее, получить верхнюю и нижнюю оценку. Для этого посчитаем среднее значение элементов гистограммы. Построим график зависимости размера файла от среднего значения:

Предвосхищая вопросы. Замечу, что на графике присутствуют два вида точек. Синие -- это множество, на котором производилось "обучение". Красные -- это точки, взятые из интернетов (картинки скачал). Как видим, они примерно укладываются в общую тенденцию. Разумеется, в данной ситуации у нас есть выбросы, которые нужно отдельно обработать и понять их причину. Кроме того, наша оценка средним значением гистограммы очень груба. А значит не следует претендовать на слишком качествеенный результат. Также отмечу, что построение гистограммы для отдельного изображения -- это затратная операция. Поэтому имеет смысл брать некотору аппроксимацию этой операции (например, брать на изображении случайные пиксели и строить гистограмму по ним).
Приведу код:
import Image import os import matplotlib.pyplot as plt import numpy as np

def Model(a, x): sum = a[0] for coeff in range(1, len(a)): sum += a[coeff] * ((x * np.sin(x)) ** coeff + np.exp(x)) return sum
listOfSize = [] listOfSizeTest = [] h = [] w = [] total = [] totalTest = [] data = []
# Перебираем все элементы из train set index = 0 for itemFile in range(0, 250): img = Image.open("/home/hedgehogues/project/testPNG/" + str(index) + ".png") img.thumbnail((300, 300), Image.ANTIALIAS) img.save("/home/hedgehogues/project/testPNG/_-1.png") tmpSize = os.path.getsize("/home/hedgehogues/project/testPNG/_-1.png") img = np.array(img.convert('L')) y = np.histogram(img, bins = range(0, 256)) total.append(np.mean(y[0] / float(np.max(y[0])))) index += 1

print index
# Перебираем все элементы из test set (картинки из интернетов) for itemFile in range(0, 6):
img = Image.open("/home/hedgehogues/project/testPNG/_" + str(itemFile) + ".png") img.thumbnail((300, 300), Image.ANTIALIAS) img.save("/home/hedgehogues/project/testPNG/_-1.png") tmpSize = os.path.getsize("/home/hedgehogues/project/testPNG/_-1.png") img = np.array(img.convert('L')) listOfSizeTest.append(tmpSize) y = np.histogram(img, bins = range(0, 256)) totalTest.append(np.mean(y[0] / float(np.max(y[0]))))
plt.plot(total, listOfSize, linestyle = '', marker = 'x') plt.plot(totalTest, listOfSizeTest, linestyle = '', marker = 'x', color = 'red') plt.show()