powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Программирование [игнор отключен] [закрыт для гостей] / Формат GIF. А как код переменной длинны "натягивается" на ЦЕЛОЕ число байт?
6 сообщений из 6, страница 1 из 1
Формат GIF. А как код переменной длинны "натягивается" на ЦЕЛОЕ число байт?
    #38929849
GIF?
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Доброе время суток, Господа.

Уже всю голову сломал. Просветите, пожалуйста, знающие.

Вот ссылка на описание формата:

http://www.r-t-f-m.info/_books/15001/index.php#appxF

А вот цитата из этого документа:

"Поскольку в результате LZW-компрессии, согласно формату GIF, генерируется массив кодов переменной длины - от 3 до 12 бит, то возникает необходимость в преобразовании этого массива в последовательную цепочку байтов, где все 8 бит были бы значащими, и эту последовательность можно было бы реально записать на диск или передать адресату. Попутно осуществляется также дополнительная компрессии графических данных. Для выполнения этой операции коды преобразуются в поток отдельных битов (порядок паковки - справа налево), а затем такой поток делится программой на одинаковые блоки по 8 бит каждый."

Вопрос: КАК? Как в общем случае непонятное (т.е. любое) количество БИТ должно в итоге "преобразоваться" в ЦЕЛОЕ КОЛИЧЕСТВО БАЙТ (по 8 бит)???
...
Рейтинг: 0 / 0
Формат GIF. А как код переменной длинны "натягивается" на ЦЕЛОЕ число байт?
    #38929906
White Owl
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Поток бит дополняется с хвоста незначащими битами (чаще всего нулями).
У нас самого начала известно сколько бит будет в потоке, поэтому незначащий хвост легко отрезать когда он перестает быть нужным.
...
Рейтинг: 0 / 0
Формат GIF. А как код переменной длинны "натягивается" на ЦЕЛОЕ число байт?
    #38929917
GIF?
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
White Owl,

Да, спасибо за ответ.
В принципе так сейчас и пробую...
Закодирую последовательность бит, а после дополню ее (битовую последовательность) нулями до целого количества байт.
...
Рейтинг: 0 / 0
Формат GIF. А как код переменной длинны "натягивается" на ЦЕЛОЕ число байт?
    #38930634
GIF?
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Нет, не выходит каменный цветок...

Может кто покажет "на пальцах": как все-таки работает этот "немного" другой lzw в gif?

Вот к примеру.
Сделал я в Paint картинку размером 3х1, т.е. три пикселя - красный, зеленый и синий:
Код: pascal
1.
($FF, $00, $00) ($00, $FF, $00) ($00, $00, $FF)



Далее сохранил я это творение в формате gif.
Открыл этот файл в HEX-редакторе, нашел там графический блок и ...

Код: pascal
1.
2.
номер: 01 02 03 04 05 06 07 08 09 10
байт:   08 06 00 B9 19 69 11 10 00 3B



Байт номер 1 = 08 - понятно, "начальный размер LZW-кода, равен глубине цвета картинки";
Байт номер 2 = 06 - понятно, "размер субблока данных, не включая сам байт";
Байт номер 9 = 00 - понятно, "терминатор блока";
Байт номер 10 = 3B - понятно, "конец файла";

Но, абхр!, что же там между ними - байты с 03 по 08?
Как биты трех исходных пикселей располагаются там?

Для этого файла Paint создал также глобальную палитру (768 байт = 256*3).
Индексы трех исходных цветов в этой палитре соответственно 9, 10 и 12.
...
Рейтинг: 0 / 0
Формат GIF. А как код переменной длинны "натягивается" на ЦЕЛОЕ число байт?
    #38930947
да хз
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
А откуда сведения что номера в палитре 9, 10 и 12?
Я смотрю на последовательность и вижу первых 3 пикселя с такими индексами: 1, 228, 203.
Остальное непонятный хлам. вообще для палитры 256 цветов 3 пикселя достаточно - 9*3 = 27 бит, что после округления = 4 байтам, непонятно зачем mspaint сделал 6 байт.
...
Рейтинг: 0 / 0
Формат GIF. А как код переменной длинны "натягивается" на ЦЕЛОЕ число байт?
    #38931896
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Я поверхностно пытался разобраться с форматом анимации gif89. В частности у меня
был вопрос - возможно или нет кодировать "спрайт" и отдельно внутри gif-файла
его анимацию. Траекторию движения (шахматные фигурки на доске)
и привязки к точкам времени.

Поскольку документ-спецификация был нудный как понедельник, я взял статью на хабре.

http://habrahabr.ru/post/127083/

и по ее мотивам воспроизвёл пример. Кое-где скопи-пастил каменты с хабра. Кое-где
добавил свои и добавил некоторые константы со спецификаций.

Получилось или - нет ХЗ. Скорее - нет поскольку анимация шахмат еще не реализована
да и сам сериализатор не иммеет никакого внятного интерфейса создания custom
изображений. Его еще пилить и пилить.

Почему я не взял готовый продукт - для рендеринга из gif4j. ХЗ. Возможно мне мешала
лицензия. А другие библиотеки не имели поддержки анимации.

Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
package mayton.web;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import java.io.IOException;
import java.io.OutputStream;
import java.io.DataOutputStream;

import static org.apache.commons.io.EndianUtils.swapShort;

/**
 * GifChessPlayer
 *
 * Links:
 *
 *      http://www.gif4j.com/download.htm
 *      https://github.com/rtyley/animated-gif-lib-for-java
 *
 * Articles:
 *
 *      http://habrahabr.ru/post/127083/
 *
 * RFCs, standards:
 *
 *      http://www.w3.org/Graphics/GIF/spec-gif89a.txt
 *
 */
public class GifChessPlayer extends HttpServlet {

    static int[] GIF_LZW_COMPRESSIONS = {3,4,5,6,7,8,9,10,11,12};

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("image/gif");
        response.setStatus(HttpServletResponse.SC_OK);
        OutputStream os = response.getOutputStream();
        DataOutputStream dos = new DataOutputStream(os);

        // ============ Header ==================

        dos.writeInt(0x47494638); // 47 49 46 38    - "GIF8"
        dos.writeShort(0x3761);   // 37 61          - "7a"

        // ============== Logical Screen Descriptor =================

        final int GIF_IMAGE_DESCRIPTOR           = 0x2c;
        final int GIF_USE_GLOBAL_COLOR_TABLE     = 0b10000000; // Локальная таблица цветов
        final int GIF_COLOR_RESOLUTION_MASK      = 0b01110000; // Цветовое разрешение. Количество цветов равно 2n+1, в нашем случае 4.
        final int GIF_SORTED_COLORS              = 0b00001000; // Цвета не отсортированы.
        final int GIF_COLOR_TABLE_SIZE           = 0b00000111; // Размер таблицы цветов. Занимает 3*2n+1 байт. У нас 12.
        final int GIF_TERMINATOR                 = 0x3b;

        // [04 00] [04 00] 4x4 (размеры logical screen)

        short width  = 4;
        short height = 4;

        dos.writeShort(swapShort(width));
        dos.writeShort(swapShort(height));

        int mask = 0; // 10010001

        mask |= GIF_USE_GLOBAL_COLOR_TABLE;
        mask |= (1 << 4) & GIF_COLOR_RESOLUTION_MASK;
        //mask |= GIF_SORTED_COLORS;
        mask |= 1 & GIF_COLOR_TABLE_SIZE;

        assert mask == 91;

        dos.writeByte(mask); // 91
        dos.writeByte(0x00); // 00
        dos.writeByte(0x00); // 00

        // ============== Global Color Table =========================

        // Near GREEN
        dos.writeByte(0x00); // 04
        dos.writeByte(0xFF); // 02
        dos.writeByte(0x00); // 04

        // Near WHITE
        dos.writeByte(0xFF);
        dos.writeByte(0xFF);
        dos.writeByte(0xFF);

        // Near RED
        dos.writeByte(0xFF);
        dos.writeByte(0x00);
        dos.writeByte(0x00);

        // Not used
        dos.writeByte(0x00);
        dos.writeByte(0x00);
        dos.writeByte(0x00);

        // ============== Image Descriptor [2c] ===================



        dos.writeByte(GIF_IMAGE_DESCRIPTOR);

        short imageX = 0;
        short imageY = 0;
        dos.writeShort(swapShort(imageX));
        dos.writeShort(swapShort(imageY));
        short imageWidth  = 4;
        short imageHeight = 4;
        dos.writeShort(swapShort(imageWidth));
        dos.writeShort(swapShort(imageHeight));
        mask = 0;
        // mask |= LOCAL_COLOR_TABLE; // Локальная таблица цветов не используется.
        // mask |= SORTED_COLORS;
        // mask |= INTERLACE;
        // mask |= RESERVED_MASK;
        // mask |= COLOR_RESOLUTION_MASK;
        dos.writeByte(mask);

        int lzwCodeLength = 2;
        dos.writeByte(lzwCodeLength); // Минимальная длина кода LZW в битах (+1).
        int sectionLength = 7;
        dos.writeByte(sectionLength); // Длина секции с данными.
        // Вы спросите: «Как! Тут же всего один байт,
        // то есть максимальная длина 255?». Верно, но таких
        // секций неограниченное число. Если файл еще не
        // закончился, то после окончания секции опять
        // встретится байт с длиной следующей секции.
        // Код может оказаться разрезанным этим байтом.
        // Нужно запоминать его, чтобы вычислить расположение следующего.

        dos.writeByte(0x84); //  10 000 100
        dos.writeByte(0x62); // 0 110 001 0
        dos.writeByte(0x18); //  000 110 00
        dos.writeByte(0x2A); // 0 010 101 0
        dos.writeByte(0x10); //  000 100 00
        dos.writeByte(0x5D); //  01 011 101
        dos.writeByte(0x00); // 0 000 000 0

        // Это коды, просто записанные подряд друг за другом. Но справа налево! Просто
        // отсчитываем нужное количество бит справа и берем это число. А если байт
        // закончился, то к уже частично полученному значению спереди дописываем число
        // (с оставшимся количеством битов) из второго байта. На практике будет понятнее.
        // Мы узнали, что минимальная длина кода LZW в битах равна 2. Но нужно прибавлять
        // еще 1, т.е. 3. Это означает, что текущий размер кода равен 3 и изначально
        // именно по столько битов будем читать.

        // === END ====
        dos.writeByte(0x00);
        // === END of file ===



        dos.writeByte(GIF_TERMINATOR);

        // LZW encoded image data.

        // Extensions

        os.flush();
    }
}
 
...
Рейтинг: 0 / 0
6 сообщений из 6, страница 1 из 1
Форумы / Программирование [игнор отключен] [закрыт для гостей] / Формат GIF. А как код переменной длинны "натягивается" на ЦЕЛОЕ число байт?
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]