示例#1
0
static void read_frame(png_structp png_ptr, png_infop info_ptr, PNG_FRAME_INFO* frame_info)
{
  unsigned int width;
  unsigned int height;
  unsigned int offset_x;
  unsigned int offset_y;
  unsigned short delay_num;
  unsigned short delay_den;
  unsigned char dop;
  unsigned char bop;
  unsigned int delay;
  unsigned char* buffer = NULL;

  png_read_frame_head(png_ptr, info_ptr);
  png_get_next_frame_fcTL(png_ptr, info_ptr, &width, &height, &offset_x, &offset_y, &delay_num, &delay_den, &dop, &bop);

  delay = 1000u * delay_num / delay_den;

  frame_info->width = width;
  frame_info->height = height;
  frame_info->offset_x = offset_x;
  frame_info->offset_y = offset_y;
  frame_info->delay = delay;
  frame_info->dop = dop;
  frame_info->bop = bop;
  frame_info->pop = IMAGE_PNG_PREPARE_UNKNOWN;

  buffer = (unsigned char*) malloc(width * height * 4);
  if (buffer == NULL) {
    frame_info->buffer = NULL;
    return;
  }

  read_image(png_ptr, buffer, width, height);
  frame_info->buffer = buffer;
}
示例#2
0
APNGDATA * loadPng(IPngReader *pSrc)
{
	png_bytep  dataFrame;
	png_uint_32 bytesPerRow;
	png_uint_32 bytesPerFrame;
    png_bytepp rowPointers;
	png_byte   sig[8];
	
	png_structp png_ptr_read;
	png_infop info_ptr_read;
	
    pSrc->read(sig,8);
    if(!png_check_sig(sig,8))
    {
        return NULL;
    }
    
    png_ptr_read = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);

    info_ptr_read = png_create_info_struct(png_ptr_read);
    
	if (setjmp(png_jmpbuf(png_ptr_read)))
    {
        png_destroy_read_struct(&png_ptr_read, &info_ptr_read, NULL);
        return NULL;
    }
        
    png_set_read_fn(png_ptr_read,pSrc,mypng_read_data);
    png_set_sig_bytes(png_ptr_read, 8);
 
    if ((png_ptr_read->bit_depth < 8) ||
        (png_ptr_read->color_type == PNG_COLOR_TYPE_PALETTE) ||
        (info_ptr_read->valid & PNG_INFO_tRNS))
        png_set_expand(png_ptr_read);

    png_set_add_alpha(png_ptr_read, 0xff, PNG_FILLER_AFTER);
    png_set_interlace_handling(png_ptr_read);
    png_set_gray_to_rgb(png_ptr_read);
    png_set_strip_16(png_ptr_read);
   
	png_read_info(png_ptr_read, info_ptr_read);
    png_read_update_info(png_ptr_read, info_ptr_read);
    
    bytesPerRow = png_ptr_read->width * 4;
    bytesPerFrame = bytesPerRow * png_ptr_read->height;
    
    APNGDATA * apng = (APNGDATA*) malloc(sizeof(APNGDATA));
    memset(apng,0,sizeof(APNGDATA));
    apng->nWid  = png_ptr_read->width;
    apng->nHei = png_ptr_read->height;
    
    //图像帧数据
    dataFrame = (png_bytep)malloc(bytesPerRow * apng->nHei);
    memset(dataFrame,0,bytesPerFrame);
    //获得扫描行指针
    rowPointers = (png_bytepp)malloc(sizeof(png_bytep)* apng->nHei);
    for(int i=0;i<apng->nHei;i++)
        rowPointers[i] = dataFrame + bytesPerRow * i;

	if (!png_get_valid(png_ptr_read, info_ptr_read, PNG_INFO_acTL))
	{//load png doesn't has this trunk.
        
        png_read_image(png_ptr_read,rowPointers);
                
        apng->pdata =dataFrame;
        apng->nFrames =1;
	}else
	{//load apng
        apng->nFrames  = png_get_num_frames(png_ptr_read, info_ptr_read);//获取总帧数

        png_bytep data = (png_bytep)malloc( bytesPerFrame * apng->nFrames);//为每一帧分配内存
        png_bytep curFrame = (png_bytep)malloc(bytesPerFrame);
        memset(curFrame,0,bytesPerFrame);
               
        apng->nLoops = png_get_num_plays(png_ptr_read, info_ptr_read);
        apng->pDelay = (unsigned short*)malloc(sizeof(unsigned short)*apng->nFrames);
        
        for(int iFrame = 0;iFrame<apng->nFrames;iFrame++)
        {
            //读帧信息头
            png_read_frame_head(png_ptr_read, info_ptr_read);
            
            //计算出帧延时信息
            if (png_get_valid(png_ptr_read, info_ptr_read, PNG_INFO_fcTL))
            {
                png_uint_16 delay_num = info_ptr_read->next_frame_delay_num,
                            delay_den = info_ptr_read->next_frame_delay_den;
            
                if (delay_den==0 || delay_den==100)
                    apng->pDelay[iFrame] = delay_num;
                else
                    if (delay_den==10)
                        apng->pDelay[iFrame] = delay_num*10;
                    else
                        if (delay_den==1000)
                            apng->pDelay[iFrame] = delay_num/10;
                        else
                            apng->pDelay[iFrame] = delay_num*100/delay_den;
            }else
            {
                apng->pDelay[iFrame] = 0;
            }
            //读取PNG帧到dataFrame中,不含偏移数据
            png_read_image(png_ptr_read, rowPointers);
            {//将当前帧数据绘制到当前显示帧中:1)获得绘制的背景;2)计算出绘制位置; 3)使用指定的绘制方式与背景混合


                //1)计算出绘制位置
                png_bytep lineDst=curFrame+info_ptr_read->next_frame_y_offset*bytesPerRow + 4 * info_ptr_read->next_frame_x_offset;
                png_bytep lineSour=dataFrame;
                //2)使用指定的绘制方式与背景混合
                switch(info_ptr_read->next_frame_blend_op)
                {
                case PNG_BLEND_OP_OVER:
                    {
                        for(unsigned int y=0;y<info_ptr_read->next_frame_height;y++)
                        {
                            png_bytep lineDst1=lineDst;
                            png_bytep lineSour1=lineSour;
                            for(unsigned int x=0;x<info_ptr_read->next_frame_width;x++)
                            {
                                png_byte alpha = lineSour1[3];
                                *lineDst1++ = ((*lineDst1)*(255-alpha)+(*lineSour1++)*alpha)>>8;
                                *lineDst1++ = ((*lineDst1)*(255-alpha)+(*lineSour1++)*alpha)>>8;
                                *lineDst1++ = ((*lineDst1)*(255-alpha)+(*lineSour1++)*alpha)>>8;
                                *lineDst1++ = ((*lineDst1)*(255-alpha)+(*lineSour1++)*alpha)>>8;
                            }
                            lineDst += bytesPerRow;
                            lineSour+= bytesPerRow;
                        }
                    }
                    break;
                case PNG_BLEND_OP_SOURCE:
                    {
                        for(unsigned int  y=0;y<info_ptr_read->next_frame_height;y++)
                        {
                            memcpy(lineDst,lineSour,info_ptr_read->next_frame_width*4);
                            lineDst += bytesPerRow;
                            lineSour+= bytesPerRow;
                        }
                    }
                    break;
                default:
                    SASSERT(FALSE);
                    break;
                }
                
                png_bytep targetFrame = data + bytesPerFrame * iFrame;
                memcpy(targetFrame,curFrame,bytesPerFrame);

                lineDst=curFrame+info_ptr_read->next_frame_y_offset*bytesPerRow + 4 * info_ptr_read->next_frame_x_offset;

                //3)处理当前帧绘制区域
                switch(info_ptr_read->next_frame_dispose_op)
                {
                case PNG_DISPOSE_OP_BACKGROUND://clear background
                    {
                        for(unsigned int y=0;y<info_ptr_read->next_frame_height;y++)
                        {
                            memset(lineDst,0,info_ptr_read->next_frame_width*4);
                            lineDst += bytesPerRow;
                        }

                    }
                    break;
                case PNG_DISPOSE_OP_PREVIOUS://copy previous frame
                    if(iFrame>0)
                    {
                        memcpy(curFrame,targetFrame-bytesPerFrame,bytesPerFrame);
                    }
                    break;
                case PNG_DISPOSE_OP_NONE://using current frame, doing nothing
                    break;
                default:
                    SASSERT(0);
                    break;
                }
            }

        }
        free(curFrame);
        free(dataFrame);
        apng->pdata =data;
	}
    free(rowPointers);

	png_read_end(png_ptr_read,info_ptr_read);
	
    png_destroy_read_struct(&png_ptr_read, &info_ptr_read, NULL);
    return apng;    
}
示例#3
0
void Openchunk::run()
{
		png_structp png_ptr_read;
    png_infop info_ptr_read;
    png_structp png_ptr_write;
    png_infop info_ptr_write;
	
    png_uint_32 next_frame_width;
    png_uint_32 next_frame_height;
    png_uint_32 next_frame_x_offset;
    png_uint_32 next_frame_y_offset;
    png_uint_16 next_frame_delay_num;
    png_uint_16 next_frame_delay_den;
    png_byte next_frame_dispose_op;
    png_byte next_frame_blend_op;
    png_color_16p Framebg;
	  framlist.clear();
	
  buffer = new StreamFile();
  buffer->LoadFile(subfile);
	qDebug() << "### start read ->" << subfile;
	if (!buffer->isValid()) {
		alert("unvalid buffer fill",__LINE__);
		exit(0);
	}
	validpng = buffer->device()->peek(4).contains("PNG");
	qDebug() << "### ahed  ->" << validpng;
	frame1.loadFromData(buffer->stream()); /* load first frame */
	if (frame1.isNull()) {
		alert("unable find a valid image",__LINE__);
		return;
	}
	png_ptr_read = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
	if(png_ptr_read == NULL) {
		alert("unable to create read struct",__LINE__);
		return;
	}
	info_ptr_read = png_create_info_struct(png_ptr_read);
	if(info_ptr_read == NULL) {
     alert("unable to create info struct",__LINE__);
		 return;
	}

	png_set_read_fn(png_ptr_read,buffer,EncoderReaderCallback);
	
	if(setjmp(png_ptr_read->jmpbuf)) {
        alert("something didn't work, jump 1",__LINE__);
		    return;
	}
	
	png_read_info(png_ptr_read, info_ptr_read);
	
	if(!png_get_valid(png_ptr_read, info_ptr_read, PNG_INFO_acTL)) {
			alert("source image must be animated",__LINE__);
		  return;
	}
	
	  QRect Frect(0,0,info_ptr_read->width,info_ptr_read->height);
    ////////////qDebug() << "### Frame rect from head ->" << Frect;
    QImage master(Frect.width(),Frect.height(),QImage::Format_ARGB32);
    const uint height = master.height();
    png_bytep *row_pointers = new png_bytep[height];
                        for (uint i = 0; i < height; ++i)  {
                          row_pointers[i] = (png_bytep)master.scanLine(i);
                        }
    int validloop = -1;
    for(int i = 0; i < png_get_num_frames(png_ptr_read, info_ptr_read); i++)
    {
        /////////qDebug() << "### frame read  ------------- " << i;
				png_ptr_write = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
        if(png_ptr_write == NULL)  {
        alert("unable to create write struct");
        return;
        }
        StreamFile *framer = new StreamFile();
        png_set_write_fn(png_ptr_write,framer,EncoderWriteCallback, NULL);
        info_ptr_write = png_create_info_struct(png_ptr_write);
        if(info_ptr_write == NULL)  {
        alert("unable to create write struct");
        return;
        }
        if(setjmp(png_ptr_write->jmpbuf))  {
            alert("something didn't work, jump 2");
            return;
        }
				png_read_frame_head(png_ptr_read, info_ptr_read);
				if(png_get_valid(png_ptr_read, info_ptr_read, PNG_INFO_fcTL))
        {
            png_get_next_frame_fcTL(png_ptr_read, info_ptr_read,
                                    &next_frame_width, &next_frame_height,
                                    &next_frame_x_offset, &next_frame_y_offset,
                                    &next_frame_delay_num, &next_frame_delay_den,
                                    &next_frame_dispose_op, &next_frame_blend_op);
        }
        else
        {
            /* the first frame doesn't have an fcTL so it's expected to be hidden, 
            * but we'll extract it anyway  next_frame_x_offset , next_frame_y_offset */ 
            next_frame_width = png_get_image_width(png_ptr_read, info_ptr_read);
            next_frame_height = png_get_image_height(png_ptr_read, info_ptr_read);
        }
				QRect C_frame_rect(0,0,next_frame_width,next_frame_height);
				
				
				AFRAMES FrameInfo = OneFrameReader(png_ptr_read, info_ptr_read, png_ptr_write, info_ptr_write,
        next_frame_width, next_frame_height);
				png_write_info(png_ptr_write, info_ptr_write);
				png_read_image(png_ptr_read, row_pointers);
        png_write_image(png_ptr_write, row_pointers);
        png_write_end(png_ptr_write, NULL);
				
				            float Fraction = (float)next_frame_delay_num /  (float)next_frame_delay_den + 0.00;
                    ////////qDebug() << "### Fraction  " << Fraction;
                    int PlayGo;
                    if (Fraction < 0.001 ) {
                        PlayGo = 100;
                    } else if (Fraction < 1.010 && Fraction > 0.9) {
                        PlayGo = 1000;
                    } else {
                        PlayGo = Fraction * 1000;
                    }
										
				/* extract frames */
				if ( framer->isValid() && Frect.contains(C_frame_rect) ) {
					 validloop++;
					 int Coalpha = 255;
					 /* prepare image if no background find grab a pixel color! */
					 QImage tmpgd(C_frame_rect.width(),C_frame_rect.height(),QImage::Format_ARGB32);
					 /* compose it files */
					 APNGFRAME one;
					 one.dimg = framer->stream();
					 one.maxframe = Frect;
					 one.pos = validloop;
					 one.point = QPoint(next_frame_x_offset,next_frame_y_offset);
					 one.play = PlayGo;
					 if (!(png_get_valid(png_ptr_read, info_ptr_read, PNG_INFO_bKGD))) {
					 tmpgd.loadFromData(one.dimg);
					 QRgb GrepColor = tmpgd.pixel(QPoint(2,2));
					 one.bg = QColor(GrepColor);
					 one.bg.setAlpha(qAlpha(GrepColor));
					 Coalpha = qAlpha(GrepColor);
					 } else {
					 one.bg = FrameInfo.bg; 
					 }
					 
					       QImage tmpe;
					       QImage Pvidi(one.maxframe.width(),one.maxframe.height(),QImage::Format_ARGB32);
					       if (tmpe.loadFromData(one.dimg)) {
								 QPainter p(&Pvidi);
								 p.setRenderHint(QPainter::Antialiasing, true);
								 p.setBrush(one.bg);
								 p.drawRect(Pvidi.rect());
								 p.drawImage(one.point,tmpe);
								 p.end();
								 one.item = Pvidi; 
                 ////qDebug() << "### isNull() in theard .." << one.item.isNull();									 
								 }
					 
					 
					 //////item tmpe
					 //////qDebug() << "### Frame rect ->" << one.point << ",nr." << validloop << "C." << one.bg.name() << "Al." << Coalpha;
					 framlist.insert(validloop,one);
				}
				framer->~StreamFile();
				png_ptr_write = 0;
        info_ptr_write = 0;
		}
	
	
	qDebug() << "### Frame size() ->" << framlist.size();
	//////alert("end of chunks",__LINE__);
	validpng = true;
	buffer->~StreamFile();
	exit(0);
}
示例#4
0
static void readAnimated( imageCache &cache, PngInfo& png ){
	auto width  = png.width();
	auto height = png.height();
	png_uint_32 x_offset=0, y_offset=0;
	png_uint_16 delay_num=0, delay_den=0;
	png_byte dispose_op = PNG_DISPOSE_OP_NONE, blend_op = PNG_BLEND_OP_SOURCE;
	
	QImage canvas( width, height, QImage::Format_ARGB32 );
	canvas.fill( qRgba( 0,0,0,0 ) );
	AnimCombiner combiner( canvas );
	
	if( setjmp( png_jmpbuf( png.png ) ) )
		return;
	
	unsigned repeats = png_get_num_plays( png.png, png.info );
	unsigned frames = png_get_num_frames( png.png, png.info );
	
	//NOTE: We discard the frame if it is not a part of the animation
	if( png_get_first_frame_is_hidden( png.png, png.info ) ){
		readImage( png, width, height );
		--frames; //libpng appears to tell the total amount of images
	}
	
	cache.set_info( frames, true, repeats>0 ? repeats-1 : -1 );
	
	for( unsigned i=0; i < frames; ++i ){
		png_read_frame_head( png.png, png.info );
		
		if( png_get_valid( png.png, png.info, PNG_INFO_fcTL ) ){
			png_get_next_frame_fcTL( png.png, png.info
				,	&width, &height
				,	&x_offset, &y_offset
				,	&delay_num, &delay_den
				,	&dispose_op, &blend_op
				);
		}
		else{
			width  = png.width();
			height = png.height();
		}
		
		readImage( png, width, height, i==0 );
		
		//Calculate delay
		delay_den = delay_den==0 ? 100 : delay_den;
		unsigned delay = std::ceil( (double)delay_num / delay_den * 1000 );
		if( delay == 0 )
			delay = 1; //Fastest speed we support
		
		//Compose and add
		auto blend_mode = blend_op == PNG_BLEND_OP_SOURCE ? BlendMode::OVERLAY : BlendMode::REPLACE;
		auto dispose_mode = [=](){ switch( dispose_op ){
				case PNG_DISPOSE_OP_NONE:       return DisposeMode::NONE;
				case PNG_DISPOSE_OP_BACKGROUND: return DisposeMode::BACKGROUND;
				case PNG_DISPOSE_OP_PREVIOUS:   return DisposeMode::REVERT;
				default: return DisposeMode::NONE; //TODO: add error
			} }();
		QImage output = combiner.combine( png.frame, x_offset, y_offset, blend_mode, dispose_mode );
		cache.add_frame( output, delay );
	}
}