mirror of
				https://github.com/LadybirdBrowser/ladybird.git
				synced 2025-10-31 05:10:57 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			91 lines
		
	
	
	
		
			4.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			91 lines
		
	
	
	
		
			4.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*
 | |
|  * Copyright (c) 2023, Nico Weber <thakis@chromium.org>
 | |
|  *
 | |
|  * SPDX-License-Identifier: BSD-2-Clause
 | |
|  */
 | |
| 
 | |
| #include <AK/Debug.h>
 | |
| #include <AK/Endian.h>
 | |
| #include <AK/Format.h>
 | |
| #include <AK/MemoryStream.h>
 | |
| #include <AK/Vector.h>
 | |
| #include <LibGfx/ImageFormats/WebPLoaderLossy.h>
 | |
| 
 | |
| // Lossy format: https://datatracker.ietf.org/doc/html/rfc6386
 | |
| 
 | |
| namespace Gfx {
 | |
| 
 | |
| // https://developers.google.com/speed/webp/docs/riff_container#simple_file_format_lossy
 | |
| // https://datatracker.ietf.org/doc/html/rfc6386#section-19 "Annex A: Bitstream Syntax"
 | |
| ErrorOr<VP8Header> decode_webp_chunk_VP8_header(ReadonlyBytes vp8_data)
 | |
| {
 | |
|     if (vp8_data.size() < 10)
 | |
|         return Error::from_string_literal("WebPImageDecoderPlugin: 'VP8 ' chunk too small");
 | |
| 
 | |
|     // FIXME: Eventually, this should probably call into LibVideo/VP8,
 | |
|     // and image decoders should move into LibImageDecoders which depends on both LibGfx and LibVideo.
 | |
|     // (LibVideo depends on LibGfx, so LibGfx can't depend on LibVideo itself.)
 | |
| 
 | |
|     // https://datatracker.ietf.org/doc/html/rfc6386#section-4 "Overview of Compressed Data Format"
 | |
|     // "The decoder is simply presented with a sequence of compressed frames [...]
 | |
|     //  The first frame presented to the decompressor is [...] a key frame.  [...]
 | |
|     //  [E]very compressed frame has three or more pieces. It begins with an uncompressed data chunk comprising 10 bytes in the case of key frames"
 | |
| 
 | |
|     u8 const* data = vp8_data.data();
 | |
| 
 | |
|     // https://datatracker.ietf.org/doc/html/rfc6386#section-9.1 "Uncompressed Data Chunk"
 | |
|     u32 frame_tag = data[0] | (data[1] << 8) | (data[2] << 16);
 | |
|     bool is_key_frame = (frame_tag & 1) == 0; // https://www.rfc-editor.org/errata/eid5534
 | |
|     u8 version = (frame_tag & 0xe) >> 1;
 | |
|     bool show_frame = (frame_tag & 0x10) != 0;
 | |
|     u32 size_of_first_partition = frame_tag >> 5;
 | |
| 
 | |
|     if (!is_key_frame)
 | |
|         return Error::from_string_literal("WebPImageDecoderPlugin: 'VP8 ' chunk not a key frame");
 | |
| 
 | |
|     if (!show_frame)
 | |
|         return Error::from_string_literal("WebPImageDecoderPlugin: 'VP8 ' chunk has invalid visibility for webp image");
 | |
| 
 | |
|     if (version > 3)
 | |
|         return Error::from_string_literal("WebPImageDecoderPlugin: unknown version number in 'VP8 ' chunk");
 | |
| 
 | |
|     u32 start_code = data[3] | (data[4] << 8) | (data[5] << 16);
 | |
|     if (start_code != 0x2a019d) // https://www.rfc-editor.org/errata/eid7370
 | |
|         return Error::from_string_literal("WebPImageDecoderPlugin: 'VP8 ' chunk invalid start_code");
 | |
| 
 | |
|     // "The scaling specifications for each dimension are encoded as follows.
 | |
|     //   0     | No upscaling (the most common case).
 | |
|     //   1     | Upscale by 5/4.
 | |
|     //   2     | Upscale by 5/3.
 | |
|     //   3     | Upscale by 2."
 | |
|     // This is a display-time operation and doesn't affect decoding."
 | |
|     u16 width_and_horizontal_scale = data[6] | (data[7] << 8);
 | |
|     u16 width = width_and_horizontal_scale & 0x3fff;
 | |
|     u8 horizontal_scale = width_and_horizontal_scale >> 14;
 | |
| 
 | |
|     u16 heigth_and_vertical_scale = data[8] | (data[9] << 8);
 | |
|     u16 height = heigth_and_vertical_scale & 0x3fff;
 | |
|     u8 vertical_scale = heigth_and_vertical_scale >> 14;
 | |
| 
 | |
|     dbgln_if(WEBP_DEBUG, "version {}, show_frame {}, size_of_first_partition {}, width {}, horizontal_scale {}, height {}, vertical_scale {}",
 | |
|         version, show_frame, size_of_first_partition, width, horizontal_scale, height, vertical_scale);
 | |
| 
 | |
|     return VP8Header { version, show_frame, size_of_first_partition, width, horizontal_scale, height, vertical_scale, vp8_data.slice(10) };
 | |
| }
 | |
| 
 | |
| ErrorOr<NonnullRefPtr<Bitmap>> decode_webp_chunk_VP8_contents(VP8Header const& vp8_header, bool include_alpha_channel)
 | |
| {
 | |
|     auto bitmap_format = include_alpha_channel ? BitmapFormat::BGRA8888 : BitmapFormat::BGRx8888;
 | |
| 
 | |
|     // Uncomment this to test ALPH decoding for WebP-lossy-with-alpha images while lossy decoding isn't implemented yet.
 | |
| #if 0
 | |
|     return Bitmap::create(bitmap_format, { vp8_header.width, vp8_header.height });
 | |
| #else
 | |
|     // FIXME: Implement webp lossy decoding.
 | |
|     (void)vp8_header;
 | |
|     (void)bitmap_format;
 | |
|     return Error::from_string_literal("WebPImageDecoderPlugin: decoding lossy webps not yet implemented");
 | |
| #endif
 | |
| }
 | |
| 
 | |
| }
 | 
