Image* PVRTCDecoder::Decode(DataStream* ds) { PVRTexHeader header; if (!ds) return 0; if ( ds->Read((Byte*)&header, sizeof(header))!=sizeof(header) ) return 0; if ( header.pvrTag[0] != gPVRTexIdentifier[0] || header.pvrTag[1] != gPVRTexIdentifier[1] || header.pvrTag[2] != gPVRTexIdentifier[2] || header.pvrTag[3] != gPVRTexIdentifier[3] ) return 0; /// @todo swap bytes ordering UInt32 formatFlags = SwapLittleToHost(header.flags) & PVR_TEXTURE_FLAG_TYPE_MASK; if ( formatFlags != kPVRTextureFlagTypePVRTC_2 && formatFlags != kPVRTextureFlagTypePVRTC_4 ) { return 0; } //bool haveAlpha = SwapLittleToHost(header.bitmaskAlpha); UInt32 width = SwapLittleToHost(header.width); UInt32 height = SwapLittleToHost(header.height); UInt32 dataLength = SwapLittleToHost(header.dataLength); UInt32 blockSize = 0; UInt32 widthBlocks = 0; UInt32 heightBlocks = 0; UInt32 bpp = 0; ImageFormat format; if (formatFlags == kPVRTextureFlagTypePVRTC_4) { blockSize = 4 * 4; // Pixel by pixel block size for 4bpp widthBlocks = width / 4; heightBlocks = height / 4; bpp = 4; format = IMAGE_FORMAT_PVRTC_4; } else { blockSize = 8 * 4; // Pixel by pixel block size for 2bpp widthBlocks = width / 8; heightBlocks = height / 4; bpp = 2; format = IMAGE_FORMAT_PVRTC_2; } // Clamp to minimum number of blocks if (widthBlocks < 2) widthBlocks = 2; if (heightBlocks < 2) heightBlocks = 2; UInt32 dataSize = widthBlocks * heightBlocks * ((blockSize * bpp) / 8); if ( dataSize < dataLength ) return 0; DataImpl* buffer = new DataImpl( dataSize ); if ( ds->Read(buffer->GetDataPtr(), dataSize )!=dataSize ) { buffer->Release(); return 0; } return new ImageImpl(width,height,format,buffer); }
bool GHL_CALL ImageImpl::Convert(ImageFormat fmt) { if (fmt==m_fmt) return true; if (!m_data) return false; const Byte* original = m_data->GetData(); if (fmt==IMAGE_FORMAT_RGB) { size_t len = m_width*m_height; DataImpl* buffer = new DataImpl( len * 3 ); Byte* data = buffer->GetDataPtr(); if (m_fmt==IMAGE_FORMAT_RGBA) { for (size_t i=0;i<len;i++) { data[i*3+0]=original[i*4+0]; data[i*3+1]=original[i*4+1]; data[i*3+2]=original[i*4+2]; } } else if (m_fmt==IMAGE_FORMAT_GRAY) { for (size_t i=0;i<len;i++) { data[i*3+0]=original[i]; data[i*3+1]=original[i]; data[i*3+2]=original[i]; } } m_data->Release(); m_data = buffer; } else if (fmt==IMAGE_FORMAT_RGBA) { size_t len = m_width*m_height; DataImpl* buffer = new DataImpl( len * 4 ); Byte* data = buffer->GetDataPtr(); if (m_fmt==IMAGE_FORMAT_RGB) { for (size_t i=0;i<len;i++) { data[i*4+0]=original[i*3+0]; data[i*4+1]=original[i*3+1]; data[i*4+2]=original[i*3+2]; data[i*4+3]=0xff; } } else if (m_fmt==IMAGE_FORMAT_GRAY) { for (size_t i=0;i<len;i++) { data[i*4+0]=original[i]; data[i*4+1]=original[i]; data[i*4+2]=original[i]; data[i*4+3]=0xff; } } m_data->Release(); m_data = buffer; } else { return false; } m_fmt = fmt; return true; }
Image* GHL_CALL ImageImpl::SubImage(UInt32 x,UInt32 y,UInt32 w,UInt32 h) const { if (!m_data) return 0; if (x>m_width) return 0; if (y>m_height) return 0; if (w>m_width) return 0; if (h>m_height) return 0; if ((x+w)>m_width) return 0; if ((y+h)>m_height) return 0; DataImpl* res = new DataImpl( w * h * GetBpp() ); Byte* data = m_data->GetDataPtr(); for (UInt32 _y = 0; _y<h;_y++) { const Byte* src = data + (_y+y)*m_width*GetBpp(); src+=x*GetBpp(); Byte* dst = res->GetDataPtr()+_y*w*GetBpp(); ::memcpy(dst,src,w*GetBpp()); } return new ImageImpl( w, h, GetFormat(), res ); }
Image* JpegDecoder::Decode(DataStream* file) { if (!file) return 0; ImageImpl* img = 0; size_t file_size = 0; file->Seek(0,F_SEEK_END); file_size = file->Tell(); file->Seek(0,F_SEEK_BEGIN); Byte **rowPtr=0; Byte* input = new Byte[file_size]; file->Read(input, UInt32(file_size)); // allocate and initialize JPEG decompression object struct jpeg_decompress_struct cinfo; struct ghl_jpeg_error_mgr jerr; //We have to set up the error handler first, in case the initialization //step fails. (Unlikely, but it could happen if you are out of memory.) //This routine fills in the contents of struct jerr, and returns jerr's //address which we place into the link field in cinfo. cinfo.err = jpeg_std_error(&jerr.pub); cinfo.err->error_exit = ghl_jpeg_error_exit; cinfo.err->output_message = ghl_jpeg_output_message; // compatibility fudge: // we need to use setjmp/longjmp for error handling as gcc-linux // crashes when throwing within external c code if (setjmp(jerr.setjmp_buffer)) { // If we get here, the JPEG code has signaled an error. // We need to clean up the JPEG object and return. jpeg_destroy_decompress(&cinfo); delete [] input; // if the row pointer was created, we delete it. if (rowPtr) delete [] rowPtr; delete img; // return null pointer return 0; } // Now we can initialize the JPEG decompression object. jpeg_create_decompress(&cinfo); // specify data source jpeg_source_mgr jsrc; // Set up data pointer jsrc.bytes_in_buffer = file_size; jsrc.next_input_byte = (JOCTET*)input; cinfo.src = &jsrc; jsrc.init_source = ghl_jpeg_init_source; jsrc.fill_input_buffer = ghl_jpeg_fill_input_buffer; jsrc.skip_input_data = ghl_jpeg_skip_input_data; jsrc.resync_to_restart = jpeg_resync_to_restart; jsrc.term_source = ghl_jpeg_term_source; // Decodes JPG input from whatever source // Does everything AFTER jpeg_create_decompress // and BEFORE jpeg_destroy_decompress // Caller is responsible for arranging these + setting up cinfo // read file parameters with jpeg_read_header() jpeg_read_header(&cinfo, TRUE); cinfo.out_color_space=JCS_RGB; cinfo.out_color_components=3; cinfo.do_fancy_upsampling=FALSE; // Start decompressor jpeg_start_decompress(&cinfo); // Get image data UInt32 rowspan = cinfo.image_width * cinfo.out_color_components; UInt32 width = cinfo.image_width; UInt32 height = cinfo.image_height; DataImpl* data = new DataImpl(width*height*3); img = new ImageImpl(width,height,IMAGE_FORMAT_RGB,data); Byte* output = data->GetDataPtr(); // Here we use the library's state variable cinfo.output_scanline as the // loop counter, so that we don't have to keep track ourselves. // Create array of row pointers for lib rowPtr = new Byte* [height]; for( size_t i = 0; i < height; i++ ) rowPtr[i] = &output[ i * rowspan ]; UInt32 rowsRead = 0; while( cinfo.output_scanline < cinfo.output_height ) rowsRead += jpeg_read_scanlines( &cinfo, &rowPtr[rowsRead], cinfo.output_height - rowsRead ); delete [] rowPtr; // Finish decompression jpeg_finish_decompress(&cinfo); // Release JPEG decompression object // This is an important step since it will release a good deal of memory. jpeg_destroy_decompress(&cinfo); delete [] input; return img; }