Запись в PNG файл (Go)

Модератор: Модераторы разделов

BratSinot
Сообщения: 812
ОС: Slackware64

Запись в PNG файл

Сообщение BratSinot »

Доброго времени суток!

Нужно записать изображение в PNG файл (Go держит только RGBA и не дает выбирать уровень зжатия). Почитав спецификации, написал это:

Код:

/* Copyright © 2013 DolphinCommode This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. MandelbrotbyBS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ package fpng import ( "os" "log" "bytes" "encoding/binary" "compress/zlib" "hash/crc32" ) func ihdr(w, h uint32, depth, color, compression, filter, interlace uint8) []byte { buffer := make([]byte, 13) binary.BigEndian.PutUint32(buffer[0:4], w) binary.BigEndian.PutUint32(buffer[4:8], h) buffer[8] = byte(depth) buffer[9] = byte(color) buffer[10] = byte(compression) buffer[11] = byte(filter) buffer[12] = byte(interlace) return buffer } func write_uint32(file *os.File, num uint32) (error) { buffer := make([]byte, 4) binary.BigEndian.PutUint32(buffer, num) _, err := file.Write(buffer) return err } func write_chunk(file *os.File, name string, data []byte) { write_uint32(file, uint32(len(data))) //Length _, err := file.Write([]byte(name)) //Chunk type if err != nil { log.Fatal(err) } _, err = file.Write(data) //Chunk data if err != nil { log.Fatal(err) } crc := crc32.ChecksumIEEE([]byte(name+string(data))) //crc32 write_uint32(file, crc) //crc32 } func Write(file *os.File, x, y uint32, img []uint8, level int) { _, err := file.Write([]byte("\x89PNG\x0D\x0A\x1A\x0A")) if err != nil { log.Fatal(err) } write_chunk(file, "IHDR", ihdr(x, y, 8, 2, 0, 0, 0)) //ihdr var cdata bytes.Buffer if err != nil { log.Fatal(err) } ccdata, err := zlib.NewWriterLevel(&cdata, level) if err != nil { log.Fatal(err) } _, err = ccdata.Write(img) if err != nil { log.Fatal(err) } write_chunk(file, "IDAT", cdata.Bytes()) ccdata.Close() write_chunk(file, "IEND", []byte{}) }

В итоге, если попытаться открыть файл ImageMagick (display), он выдает ошибку:

Код: Выделить всё

display: Ignoring bad adaptive filter type `out.png' @ warning/png.c/MagickPNGWarningHandler/1787.
display: Not enough image data `out.png' @ error/png.c/MagickPNGErrorHandler/1761.
display: corrupt image `out.png' @ error/png.c/ReadPNGImage/3903.


Чанки формирую и записываю правильно. Использую только минимум: IHDR, IDAT, IEND.
Спасибо сказали:
Аватара пользователя
drBatty
Сообщения: 8735
Статус: GPG ID: 4DFBD1D6 дом горит, козёл не видит...
ОС: Slackware-current

Re: Запись в PNG файл

Сообщение drBatty »

BratSinot писал(а):
08.04.2013 01:50
Чанки формирую и записываю правильно.

неправильно.

сравните, что получается с тем, что делает например GIMP.
http://emulek.blogspot.ru/ Windows Must Die
Учебник по sed зеркало в github

Скоро придёт
Осень
Спасибо сказали:
BratSinot
Сообщения: 812
ОС: Slackware64

Re: Запись в PNG файл

Сообщение BratSinot »

drBatty писал(а):
08.04.2013 07:58
BratSinot писал(а):
08.04.2013 01:50
Чанки формирую и записываю правильно.

неправильно.

сравните, что получается с тем, что делает например GIMP.

Сравнивал IHDR и IEND, они были одинаковыми. А что неправильно? <длинна><имя><данные><crc32>. crc считается из <имя><данные>.

pngtopnm выдал:

Код: Выделить всё

pngtopnm: fatal libpng error: Not enough image data

Но почему не хватает, если IHDR, IDAT и IEND достаточно для изображения?

Сейчас создал GIMP'ом изображение 128x128 RGB. И оно отличается от моего только степенью сжатости, т.к. GIMP похоже какой-то фильтр применяет.
Спасибо сказали:
NickLion
Сообщения: 3408
Статус: аватар-невидимка
ОС: openSUSE Tumbleweed x86_64

Re: Запись в PNG файл

Сообщение NickLion »

Можете привести полную работоспособную программу?
Спасибо сказали:
BratSinot
Сообщения: 812
ОС: Slackware64

Re: Запись в PNG файл

Сообщение BratSinot »

NickLion писал(а):
08.04.2013 11:27
Можете привести полную работоспособную программу?

Код: Выделить всё

package main

import (
    "os"
    "log"

    "fpng"
)

const resox, resoy = 128, resox

func main() {
    img := make([]uint8, resox*resoy*3)

    for x:=0; x<resox; x++ {
        for y:=0; y<resoy; y++ {
            img[(x+y*resox)*3+0] = 255
            img[(x+y*resox)*3+1] = 0
            img[(x+y*resox)*3+2] = 0
        }
    }

    file, err := os.Create("out.png")
    if err != nil {
        log.Fatal(err)
    }
    fpng.Write(file, resox, resoy, 0)
    file.Close()
}
Спасибо сказали:
NickLion
Сообщения: 3408
Статус: аватар-невидимка
ОС: openSUSE Tumbleweed x86_64

Re: Запись в PNG файл

Сообщение NickLion »

Что-то у меня пропал инет, отвечаю с телефона. Работающую программу ещё не смотрел, но беглым просмотром функции Write заметил, что отсутствует байт метода фильтрации, который требуется в RFC 2083 пункт 4.1.3 перед каждым scanline.
Спасибо сказали:
BratSinot
Сообщения: 812
ОС: Slackware64

Re: Запись в PNG файл

Сообщение BratSinot »

NickLion писал(а):
08.04.2013 12:06
Что-то у меня пропал инет, отвечаю с телефона. Работающую программу ещё не смотрел, но беглым просмотром функции Write заметил, что отсутствует байт метода фильтрации, который требуется в RFC 2083 пункт 4.1.3 перед каждым scanline.

Дык фильтрация же не обязательна?

Код: Выделить всё

it is only necessary to insert a filter type byte before the data.

А ну да, была у меня мысль так сделать.
Спасибо сказали:
Ism
Сообщения: 1261
Статус: Никто, по сути быдло

Re: Запись в PNG файл

Сообщение Ism »

Зачем такой садизм, если можно использовать библиотеки того же ImageMagic
Спасибо сказали:
BratSinot
Сообщения: 812
ОС: Slackware64

Re: Запись в PNG файл

Сообщение BratSinot »

Ism писал(а):
08.04.2013 12:51
Зачем такой садизм, если можно использовать библиотеки того же ImageMagic

Во первых, это не садизм.
Во вторых, чтоб использовать ImageMagick в Go нужно его линковать, а это означает, что программа не будет 100% платформо-независимой.
В третьих, во всех библиотеках присуствует избыточная функцияональность. Я же реализую только то, что мне нужно и оно будет значительно быстрее работать.
В четвертых, PNG простой, просто у меня возникла проблема из-за того, что в спецификации которую я читал, про фильтры было не до конца сказано.

Ну вот, нечто подобное помогло:

Код: Выделить всё

for x:=uint32(0); x<rx; x++ {
        ccdata.Write([]byte{0})
        ccdata.Write(img[(x*3):(x*3+rx*3)])
    }
Спасибо сказали:
Ism
Сообщения: 1261
Статус: Никто, по сути быдло

Re: Запись в PNG файл

Сообщение Ism »

BratSinot писал(а):
08.04.2013 14:01
Ism писал(а):
08.04.2013 12:51
Зачем такой садизм, если можно использовать библиотеки того же ImageMagic

Во первых, это не садизм.
Во вторых, чтоб использовать ImageMagick в Go нужно его линковать, а это означает, что программа не будет 100% платформо-независимой.
В третьих, во всех библиотеках присуствует избыточная функцияональность. Я же реализую только то, что мне нужно и оно будет значительно быстрее работать.
В четвертых, PNG простой, просто у меня возникла проблема из-за того, что в спецификации которую я читал, про фильтры было не до конца сказано.

Ну вот, нечто подобное помогло:

Код: Выделить всё

for x:=uint32(0); x<rx; x++ {
        ccdata.Write([]byte{0})
        ccdata.Write(img[(x*3):(x*3+rx*3)])
    }



В Lazarus есть объект http://lazarus-ccr.sourceforge.net/docs/lc...orkgraphic.html
Наверняка подобных объектов много и на других языках

Если лицензии совпадают можно выдрать код из ImageMagic

Насчет большей скорости сомнительно, так как неизвестно какой вариант кода быстрее
Спасибо сказали:
NickLion
Сообщения: 3408
Статус: аватар-невидимка
ОС: openSUSE Tumbleweed x86_64

Re: Запись в PNG файл

Сообщение NickLion »

Ism, да ладно, велосипеды — это интресно и полезно. Никто же не говорит, что обязательно они будут использоваться.
BratSinot, PNG прост, если нужно мало форматов. Поддержка Adam7, всех методов фильтрации, разных битностей — усложнит алгоритм. Можно всегда заюзать libpng.
Спасибо сказали: