Esempio n. 1
0
/*
 * Converts a 16-bit RGB pixel to grayscale, as specified in ITU BT.601.
 */
static void
opng_reset_chroma16_bt601(png_bytep rgb16)
{
    /* Use 16-bit multiplications and 32-bit additions. */
    unsigned int r16 = png_get_uint_16(rgb16 + 0);
    unsigned int g16 = png_get_uint_16(rgb16 + 2);
    unsigned int b16 = png_get_uint_16(rgb16 + 4);
    png_uint_32 r32 = r16 * (png_uint_32)Kr_bt601;
    png_uint_32 g32 = g16 * (png_uint_32)Kg_bt601;
    png_uint_32 b32 = b16 * (png_uint_32)Kb_bt601;
    png_uint_32 y32 = r32 + g32 + b32;
    unsigned int y16 = (unsigned int)((y32 + 32767U) / 65535U);
    png_save_uint_16(rgb16 + 0, y16);
    png_save_uint_16(rgb16 + 2, y16);
    png_save_uint_16(rgb16 + 4, y16);
}
Esempio n. 2
0
/*
 * Sets the precision of a 16-bit sample to a lower value,
 * then scales the result back to 16 bits.
 */
static void
opng_set_precision16(png_bytep sample_ptr, int new_precision)
{
    unsigned int old_value = png_get_uint_16(sample_ptr);
    unsigned int chop_value = old_value >> (16 - new_precision);
    unsigned int chop_max = (1U << new_precision) - 1;
    unsigned int new_value =
        (unsigned int)
            (((png_uint_32)chop_value * 65535U + chop_max / 2) / chop_max);
    png_save_uint_16(sample_ptr, new_value);
}
Esempio n. 3
0
/*
 * @brief manually process a single chunk of apng data
 */
void apng_ani::_process_chunk()
{
	_id = _read_chunk(_chunk);

	if (_id == id_acTL && !_got_IDAT && !_got_acTL) {
		// animation control chunk
		if (!_reading) {
			return;
		}
		nframes = png_get_uint_32(&_chunk.data[8]);
		plays = png_get_uint_32(&_chunk.data[12]);

		if (!nframes || nframes > PNG_UINT_31_MAX || plays > PNG_UINT_31_MAX) {
			_apng_failed("invalid apng acTL data");
		}

		_got_acTL = true;
		_frames.reserve(nframes);
		_frame_offsets.reserve(nframes+1); // extra 1 is for EOF offset
	}
	else if (_id == id_fcTL && (!_got_IDAT || _got_acTL)) {
		// frame control chunk
		if (_reading) {
			uint sequence_num = png_get_uint_32(&_chunk.data[8]);
			if (sequence_num != _sequence_num++) {
				_apng_failed("invalid apng fcTL sequence number");
			}
		}

		// handle frame finish in next_frame
		_framew = png_get_uint_32(&_chunk.data[12]);
		_frameh = png_get_uint_32(&_chunk.data[16]);
		_x_offset = png_get_uint_32(&_chunk.data[20]);
		_y_offset = png_get_uint_32(&_chunk.data[24]);
		_delay_num = png_get_uint_16(&_chunk.data[28]);
		_delay_den = png_get_uint_16(&_chunk.data[30]);
		_dispose_op = _chunk.data[32];
		_blend_op = _chunk.data[33];

		if (_reading &&
				(_framew > cMaxPNGSize || _frameh > cMaxPNGSize
				|| _x_offset > cMaxPNGSize || _y_offset > cMaxPNGSize
				|| _x_offset + _framew > w || _y_offset + _frameh > h
				|| _dispose_op > 2 || _blend_op > 1)) {
			_apng_failed("invalid apng fcTL data");
		}

		// according to spec...
		if (current_frame == 0 && _dispose_op == 2) {
			_dispose_op = 1;
		}

		if (_delay_den == 0) _delay_den = 100; // APNG spec
		if (_delay_num == 0) _delay_num = 1;   // arbitrary lower bound
		float frame_delay = static_cast<float>(_delay_num)/static_cast<float>(_delay_den);
		frame.delay = frame_delay;

		if (_reading) {
			anim_time+= frame_delay;
			_frame_offsets.push_back((int)_offset);
		}
		else {
			if (_got_IDAT && _processing_start()) {
				_apng_failed("couldn't start fdat apng frame");
			}
		}
	}
	else if (_id == id_IDAT) {
		_got_IDAT = true;
		_processing_data(&_chunk.data[0], _chunk.size);
	}
	else if (_id == id_fdAT && _got_acTL) {
		if (_reading) {
			uint sequence_num = png_get_uint_32(&_chunk.data[8]);
			if (sequence_num != _sequence_num++) {
				_apng_failed("invalid apng fdAT sequence number");
			}
		}

		if (_reading) {
			return;
		}

		png_save_uint_32(&_chunk.data[4], _chunk.size - 16);
		memcpy(&_chunk.data[8], "IDAT", 4);
		_processing_data(&_chunk.data[4], _chunk.size - 4);
	}
	else if (_id == id_IEND) {
		return;
	}
	else if (not_chunk(_chunk.data[4]) || not_chunk(_chunk.data[5]) ||
			not_chunk(_chunk.data[6]) || not_chunk(_chunk.data[7])) {
		_apng_failed("unknown chunk ID found");
	}
	else if (!_got_IDAT) {
		_processing_data(&_chunk.data[0], _chunk.size);
		_info_chunks.push_back(_chunk);
	}
}