Rate This Document
Findability
Accuracy
Completeness
Readability

Quick Start

The following uses PNG-to-AVIF conversion as an example to describe two calling methods: CLI and C++.

CLI

  1. Set the environment variable. /home/libavif/install indicates the installation path.

    export LD_LIBRARY_PATH=/home/libavif/install/lib/:/home/libavif/install/lib64/:$LD_LIBRARY_PATH
    export PATH=/home/libavif/install/bin:$PATH
  2. Run the PNG-to-AVIF conversion program.

    avifenc input.png output.avif

C++

  1. Create a quick_start.cpp file and write the following content into the file:

    #include <avif/avif.h>
    #include <iostream>
    #include <fstream>
    #include <vector>
    #include <png.h>
    #include <stdexcept>
    #include <cstring>
    static bool decodePNGtoRGBA(const std::string& inputPath, std::vector<uint8_t>& rgbaData, int& width, int& height) {
        FILE* fp = fopen(inputPath.c_str(), "rb");
        if (!fp) {
            std::cerr << "Failed to open the file: " << inputPath << std::endl;
            return false;
        }
    
        unsigned char sig[8];
        if (fread(sig, 1, 8, fp) != 8 || png_sig_cmp(sig, 0, 8)) {
            std::cerr << "Invalid PNG file: " << inputPath << std::endl;
            fclose(fp);
            return false;
        }
    
        png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
        if (!png_ptr) {
            std::cerr << "Failed to create png_read_struct" << std::endl;
            fclose(fp);
            return false;
        }
    
        png_infop info_ptr = png_create_info_struct(png_ptr);
        if (!info_ptr) {
            std::cerr << "Failed to create png_info_struct" << std::endl;
            png_destroy_read_struct(&png_ptr, nullptr, nullptr);
            fclose(fp);
            return false;
        }
    
        if (setjmp(png_jmpbuf(png_ptr))) {
            std::cerr << "Internal error of libpng" << std::endl;
            png_destroy_read_struct(&png_ptr, &info_ptr, nullptr);
            fclose(fp);
            return false;
        }
    
        png_init_io(png_ptr, fp);
        png_set_sig_bytes(png_ptr, 8); // The 8-byte signature has been read.
    
        png_read_info(png_ptr, info_ptr);
    
        width = png_get_image_width(png_ptr, info_ptr);
        height = png_get_image_height(png_ptr, info_ptr);
        png_byte color_type = png_get_color_type(png_ptr, info_ptr);
        png_byte bit_depth = png_get_bit_depth(png_ptr, info_ptr);
    
        if (bit_depth == 16)
            png_set_strip_16(png_ptr);
    
        if (color_type == PNG_COLOR_TYPE_PALETTE)
            png_set_palette_to_rgb(png_ptr);
    
        if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
            png_set_expand_gray_1_2_4_to_8(png_ptr);
    
        if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
            png_set_tRNS_to_alpha(png_ptr);
    
        if (color_type == PNG_COLOR_TYPE_GRAY ||
            color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
            png_set_gray_to_rgb(png_ptr);
    
        if (png_get_color_type(png_ptr, info_ptr) != PNG_COLOR_TYPE_RGBA) {
            png_set_add_alpha(png_ptr, 0xFF, PNG_FILLER_AFTER);
        }
    
        png_read_update_info(png_ptr, info_ptr);
    
        size_t row_bytes = png_get_rowbytes(png_ptr, info_ptr);
        if (row_bytes != static_cast<size_t>(width) * 4) {
            std::cerr << "Warning: The expected number of bytes per line (" << width * 4 << ") does not match the actual number (" << row_bytes << "). The conversion may not have been performed as expected." << std::endl;
        }
    
        rgbaData.resize(width * height * 4);
        
        std::vector<png_bytep> row_pointers(height);
        for (int y = 0; y < height; ++y) {
            row_pointers[y] = rgbaData.data() + y * row_bytes;
        }
    
        png_read_image(png_ptr, row_pointers.data());
        png_read_end(png_ptr, nullptr);
    
        png_destroy_read_struct(&png_ptr, &info_ptr, nullptr);
        fclose(fp);
    
        The std::cout << "PNG file has been successfully decoded into the RGBA format (" << width << "x" << height << ")." << std::endl.
        return true;
    }
    
    // Encode RGBA data into an AVIF file.
    bool encodeRGBAtoAVIF(const std::string& outputPath, const uint8_t* rgbaData, int width, int height) {
        avifEncoder* encoder = avifEncoderCreate();
        if (!encoder) {
            std::cerr << "Failed to create the AVIF encoder" << std::endl;
            return false;
        }
    
        encoder->maxThreads = 8;
        encoder->minQuantizer = 19;
        encoder->maxQuantizer = 21;
        encoder->minQuantizerAlpha = 0;
        encoder->maxQuantizerAlpha = 0;
        encoder->tileRowsLog2=3;
        encoder->tileColsLog2=3;
        encoder->speed = 8;
        encoder->codecChoice = AVIF_CODEC_CHOICE_AOM;
    
        avifImage* image = avifImageCreate(width, height, 8, AVIF_PIXEL_FORMAT_YUV420);
        if (!image) {
            std::cerr << "Failed to create an AVIF image" << std::endl;
            avifEncoderDestroy(encoder);
            return false;
        }
        image->yuvFormat = AVIF_PIXEL_FORMAT_YUV420;
        image->depth = 8;
    
        avifRGBImage rgbImage;
        avifRGBImageSetDefaults(&rgbImage, image);
        rgbImage.format = AVIF_RGB_FORMAT_RGBA;
        rgbImage.depth = 8;
        rgbImage.rowBytes = width * 4;
        rgbImage.pixels = const_cast<uint8_t*>(rgbaData);
    
        if (avifImageRGBToYUV(image, &rgbImage) != AVIF_RESULT_OK) {
            std::cerr << "Failed to convert RGBA data to YUV" << std::endl;
            avifImageDestroy(image);
            avifEncoderDestroy(encoder);
            return false;
        }
    
        avifRWData output = AVIF_DATA_EMPTY;
        if (avifEncoderWrite(encoder, image, &output) != AVIF_RESULT_OK) {
            std::cerr << "Encoding failed" << std::endl;
            avifImageDestroy(image);
            avifEncoderDestroy(encoder);
            return false;
        }
    
        std::ofstream outFile(outputPath, std::ios::binary);
        if (!outFile.write(reinterpret_cast<char*>(output.data), output.size)) {
            std::cerr << "Failed to write the file" << std::endl;
            avifRWDataFree(&output);
            avifImageDestroy(image);
            avifEncoderDestroy(encoder);
            return false;
        }
    
        avifRWDataFree(&output);
        avifImageDestroy(image);
        avifEncoderDestroy(encoder);
        std::cout << "AVIF file generated: " << outputPath << std::endl;
        return true;
    }
    
    int main() {
        std::vector<uint8_t> rgbaData;
        int width = 0, height = 0;
        
        // Input and output file paths
        std::string inputPath = "input.png"; 
        std::string outputPathavif = "output.avif";
    
        // Call the PNG decoding function.
        bool decode = decodePNGtoRGBA(inputPath, rgbaData, width, height);
        
        if (!decode) {
            std::cerr << "PNG decoding failed. The program exits." << std::endl;
            return 1;
        }
    
        // Convert the format to AVIF.
        bool encodeAvif = encodeRGBAtoAVIF(outputPathavif, rgbaData.data(), width, height); 
        
        if (!encodeAvif) {
            std::cerr << "AVIF encoding failed. The program exits." << std::endl;
            return 1;
        }
    
        return 0;
    }
  2. Run the program.

    g++ -o simple_convert quick_start.cpp   -Ihome/libavif/install/include   -L/home/libavif/install/lib   -lavif -lpng -lz -lm
    ./quick_start 

    If the AVIF file is generated, the program is running normally.