Back to... PDF Writer

Source file : gid-decoding_qoi.adb



with GID.Buffering;

package body GID.Decoding_QOI is

  ----------
  -- Load --
  ----------

  procedure Load (image : in out Image_descriptor) is

    procedure Row_start (y : Natural) is
    begin
      Set_X_Y (0, Integer (image.height) - 1 - y);
    end Row_start;

    type Pixel is record
      r, g, b, a : U8;
    end record;

    run : U8 := 0;                              --  Run-Length encoding
    index : array (U8'(0) .. 63) of Pixel :=    --  Index of recent pixels
             (others => (0, 0, 0, 0));          --    (moving palette)
    px : Pixel := (0, 0, 0, 255);               --  Current pixel

    procedure Output_Pixel is
    pragma Inline (Output_Pixel);
      function Times_257 (x : Primary_color_range) return Primary_color_range is
      pragma Inline (Times_257);
      begin
        return 16 * (16 * x) + x;  --  this is 257 * x, equal to 16#0101# * x
        --  Numbers 8-bit -> no OA warning at instantiation.
        --  Returns x if type Primary_color_range is mod 2**8.
      end Times_257;
    begin
      case Primary_color_range'Modulus is
        when 256 =>
          Put_Pixel (
            Primary_color_range (px.r),
            Primary_color_range (px.g),
            Primary_color_range (px.b),
            Primary_color_range (px.a)
          );
        when 65_536 =>
          Put_Pixel (
            Times_257 (Primary_color_range (px.r)),
            Times_257 (Primary_color_range (px.g)),
            Times_257 (Primary_color_range (px.b)),
            Times_257 (Primary_color_range (px.a))
            --  Times_257 makes max intensity FF go to FFFF
          );
        when others =>
          raise invalid_primary_color_range with "Color range not supported";
      end case;
    end Output_Pixel;

    QOI_OP_INDEX : constant := 2#00_000000#;
    QOI_OP_DIFF  : constant := 2#01_000000#;
    QOI_OP_LUMA  : constant := 2#10_000000#;
    QOI_OP_RUN   : constant := 2#11_000000#;

    QOI_OP_RGB   : constant := 2#11_111110#;
    QOI_OP_RGBA  : constant := 2#11_111111#;

    QOI_MASK_1   : constant := 2#00_111111#;
    QOI_MASK_2   : constant := 2#11_000000#;

    function QOI_COLOR_HASH (C : Pixel) return U8 is
    pragma Inline (QOI_COLOR_HASH);
    begin
      return C.r * 3 + C.g * 5 + C.b * 7 + C.a * 11;
    end QOI_COLOR_HASH;

    b1, b2, vg : U8;
    eos_good : Boolean;

    use GID.Buffering;

  begin
    for y in 0 .. Integer (image.height) - 1 loop
      Row_start (y);
      for x in 0 .. Integer (image.width) - 1 loop
        if run > 0 then
          run := run - 1;
        else
          Get_Byte (image.buffer, b1);
          case b1 and QOI_MASK_2 is
            when QOI_OP_INDEX =>
              px := index (b1);
            when QOI_OP_DIFF =>
              px.r := px.r + (Shift_Right (b1, 4) and 3) - 2;
              px.g := px.g + (Shift_Right (b1, 2) and 3) - 2;
              px.b := px.b + (b1                  and 3) - 2;
            when QOI_OP_LUMA =>
              Get_Byte (image.buffer, b2);
              vg := (b1 and QOI_MASK_1) - 32;
              px.r := px.r + vg - 8 + (Shift_Right (b2, 4) and 16#0f#);
              px.g := px.g + vg;
              px.b := px.b + vg - 8 + (b2                  and 16#0f#);
            when QOI_OP_RUN =>
              case b1 is
                when QOI_OP_RGB =>
                  Get_Byte (image.buffer, px.r);
                  Get_Byte (image.buffer, px.g);
                  Get_Byte (image.buffer, px.b);
                when QOI_OP_RGBA =>
                  Get_Byte (image.buffer, px.r);
                  Get_Byte (image.buffer, px.g);
                  Get_Byte (image.buffer, px.b);
                  Get_Byte (image.buffer, px.a);
                when others =>
                  run := b1 and QOI_MASK_1;
                  --  One extra run iteration is done just here by not changing px.
              end case;
            when others => null;
          end case;
          index (QOI_COLOR_HASH (px) and QOI_MASK_1) := px;
        end if;
        Output_Pixel;
      end loop;
      Feedback (((y + 1) * 100) / Integer (image.height));
    end loop;
    --  Check end of stream signature:
    eos_good := True;
    for count in 1 .. 7 loop
      Get_Byte (image.buffer, b1);
      eos_good := eos_good and b1 = 0;
    end loop;
    Get_Byte (image.buffer, b1);
    eos_good := eos_good and b1 = 1;
    if not eos_good then
      raise error_in_image_data with "QOI format: unexpected end of stream";
    end if;
  end Load;

end GID.Decoding_QOI;


Ada PDF Writer: Ada package for writing PDF files (.pdf). Ada programming.
Some news about Ada PDF Writer and other Ada projects on Gautier's blog.