I have a byte array where each byte correlates to a pixel value of my image. These byte values are either exactly 0 or 255. The array is packed from left to right and then top to bottom. From this array I want to create a grey-scale .PNG image with a bit depth of 1. I cannot use any wrappers to zlib.
The function works as it creates a valid png file. However the image created is not correct. I am fairly certain (although possibly wrong) the problem lies with the packing of data into a byte array that I pass to the Zlib deflate function. I have read through the spec: https://www.w3.org/TR/PNG/ to no avail.
I have the following code:
#include "zlib.h"
enum E_PNGImageType
{
eGreyScale = 0,
eTrueColour = 2,
eIndexedColour = 3,
eGreyScaleAlpha = 4,
eTrueColourAlpha = 6
};
enum E_PNGBitDepth
{
eOne = 1,
eTwo = 2,
eFour = 4,
eEight = 8,
eSixteen = 16
};
enum E_PNGCompressionMethod
{
eDeflate = 0
};
enum E_PNGFilterMethod
{
eAdaptive = 0
};
enum E_PNGInterlaceMethod
{
eNone = 0,
eAdam7 = 1
};
void CreatePNG(BYTE *pData, int iWidth, int iHeight)
{
/* Convert each byte to a bit and package the bits into a byte */
std::vector<BYTE> vBitData;
int bit = 0;
BYTE value = 0;
vBitData.clear();
for (int h = 0; h < iHeight; h++)
{
for (int w = 0; w < iWidth; w++)
{
if (pData[(h * iWidth) + w] > 0)
{
value += (1 << (7 - bit));
}
bit++;
if (bit == 8)
{
bit = 0;
vBitData.push_back(value);
value = 0;
}
}
}
if (bit > 0)
{
vBitData.push_back(value);
}
GeneratePNGData(vBitData.data(), iWidth, iHeight, vBitData.size(), &vPNGData);
}
void GeneratePNGData(BYTE *pData, unsigned int uiWidth, unsigned int uiHeight, unsigned int uiSize, std::vector<BYTE> *pPNGData)
{
int iCRCStartIndex;
int iSize;
unsigned int uiCRC;
z_stream strm;
const int C_BUFFER_SIZE = 20000;
unsigned char tempBuffer[C_BUFFER_SIZE];
int iLengthDataIndex;
int iRes;
pPNGData->clear();
/* PNG Signature */
pPNGData->push_back(137);
pPNGData->push_back(80);
pPNGData->push_back(78);
pPNGData->push_back(71);
pPNGData->push_back(13);
pPNGData->push_back(10);
pPNGData->push_back(26);
pPNGData->push_back(10);
/* IDHR Image Header */
/* 4 Bytes: Chunk Length */
pPNGData->push_back(0);
pPNGData->push_back(0);
pPNGData->push_back(0);
pPNGData->push_back(13);
/* Checksum Start Index */
iCRCStartIndex = pPNGData->size();
/* 4 Bytes: Chunk Type */
pPNGData->push_back(73);
pPNGData->push_back(72);
pPNGData->push_back(68);
pPNGData->push_back(82);
/* 4 Bytes: Chunk Data - Width */
pPNGData->push_back(((BYTE*)&uiWidth)[3]);
pPNGData->push_back(((BYTE*)&uiWidth)[2]);
pPNGData->push_back(((BYTE*)&uiWidth)[1]);
pPNGData->push_back(((BYTE*)&uiWidth)[0]);
/* 4 Bytes: Chunk Data - Height */
pPNGData->push_back(((BYTE*)&uiHeight)[3]);
pPNGData->push_back(((BYTE*)&uiHeight)[2]);
pPNGData->push_back(((BYTE*)&uiHeight)[1]);
pPNGData->push_back(((BYTE*)&uiHeight)[0]);
/* 1 Byte: Chunk Data - Bit Depth */
pPNGData->push_back(E_PNGBitDepth::eOne);
/* 1 Byte: Chunk Data - Colour Type */
pPNGData->push_back(E_PNGImageType::eGreyScale);
/* 1 Byte: Chunk Data - Compression Method */
pPNGData->push_back(E_PNGCompressionMethod::eDeflate);
/* 1 Byte: Chunk Data - Filter Method */
pPNGData->push_back(E_PNGFilterMethod::eAdaptive);
/* 1 Byte: Chunk Data - Interlace Method */
pPNGData->push_back(E_PNGInterlaceMethod::eNone);
/* Size of Data to Perform Checksum Over */
iSize = pPNGData->size() - iCRCStartIndex;
/* 4 Bytes: CRC */
uiCRC = AddPNGChecksumData(&pPNGData->data()[iCRCStartIndex], iSize);
pPNGData->push_back(((BYTE*)&uiCRC)[3]);
pPNGData->push_back(((BYTE*)&uiCRC)[2]);
pPNGData->push_back(((BYTE*)&uiCRC)[1]);
pPNGData->push_back(((BYTE*)&uiCRC)[0]);
/* IDAT Image Data */
/* Length Data Offset */
iLengthDataIndex = pPNGData->size();
/* 4 Bytes: Chunk Length */
pPNGData->push_back(0);
pPNGData->push_back(0);
pPNGData->push_back(0);
pPNGData->push_back(0);
/* Checksum Start Index */
iCRCStartIndex = pPNGData->size();
/* 4 Bytes: Chunk Type */
pPNGData->push_back(73);
pPNGData->push_back(68);
pPNGData->push_back(65);
pPNGData->push_back(84);
/* Length Bytes: Chunk Data - Compressed Image Data */
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
deflateInit(&strm, Z_DEFLATED);
strm.avail_in = uiSize;
strm.next_in = pData;
strm.avail_out = C_BUFFER_SIZE;
strm.next_out = tempBuffer;
iRes = deflate(&strm, Z_FINISH);
if (iRes != Z_STREAM_END) MessageBox(NULL, "Error", "Error", 0);
pPNGData->insert(pPNGData->end(), tempBuffer, tempBuffer + strm.total_out);
deflateEnd(&strm);
/* Now Length Is Know Edit Length Field */
(*pPNGData)[iLengthDataIndex + 0] = ((BYTE*)&strm.total_out)[3];
(*pPNGData)[iLengthDataIndex + 1] = ((BYTE*)&strm.total_out)[2];
(*pPNGData)[iLengthDataIndex + 2] = ((BYTE*)&strm.total_out)[1];
(*pPNGData)[iLengthDataIndex + 3] = ((BYTE*)&strm.total_out)[0];
/* Size of Data to Perform Checksum Over */
iSize = pPNGData->size() - iCRCStartIndex;
/* 4 Bytes: CRC */
uiCRC = AddPNGChecksumData(&pPNGData->data()[iCRCStartIndex], iSize);
pPNGData->push_back(((BYTE*)&uiCRC)[3]);
pPNGData->push_back(((BYTE*)&uiCRC)[2]);
pPNGData->push_back(((BYTE*)&uiCRC)[1]);
pPNGData->push_back(((BYTE*)&uiCRC)[0]);
/* IEND Image trailer */
/* 4 Bytes: Chunk Length */
pPNGData->push_back(0);
pPNGData->push_back(0);
pPNGData->push_back(0);
pPNGData->push_back(0);
/* Checksum Start Index */
iCRCStartIndex = pPNGData->size();
/* 4 Bytes: Chunk Type */
pPNGData->push_back(73);
pPNGData->push_back(69);
pPNGData->push_back(78);
pPNGData->push_back(68);
/* Size of Data to Perform Checksum Over */
iSize = pPNGData->size() - iCRCStartIndex;
/* 4 Bytes: CRC */
uiCRC = AddPNGChecksumData(&pPNGData->data()[iCRCStartIndex], iSize);
pPNGData->push_back(((BYTE*)&uiCRC)[3]);
pPNGData->push_back(((BYTE*)&uiCRC)[2]);
pPNGData->push_back(((BYTE*)&uiCRC)[1]);
pPNGData->push_back(((BYTE*)&uiCRC)[0]);
/* Temp Debug Code */
FILE* pFile;
fopen_s(&pFile, "DEBUG_IMAGES\\zzz_test_output.png", "wb");
fwrite((*pPNGData).data(), 1, pPNGData->size(), pFile);
fclose(pFile);
}
You need to push an 8-bit zero at the beginning of each row (at the beginning of the loop on h in your code). That's the "filter type" byte, which in your case should be 0, meaning "no filtering".
The filter method "0" in IHDR simply says that the IDAT contains a filter byte at the beginning of each row. The option is there in IHDR to allow other methods, such as omitting those bytes and assuming a "0" filter type for each row. In the end, the PNG authors never approved any method other than the filter-byte-per-row method.
Also the check on bit>0 needs to be done at the end of the loop on h -- just move the closing bracket on the h-loop down below it, and reset value=0 there as well, so each row will be padded out to fill the final byte.
Related
I have input from captured camera frame as CMSampleBufferRef and I need to get the raw pixels preferably in C type uint8_t[].
I also need to find the color scheme of the input image.
I know how to convert CMSampleBufferRef to UIImage and then to NSData with png format but I dont know how to get the raw pixels from there. Perhaps I could get it already from CMSampleBufferRef/CIImage`?
This code shows the need and the missing bits.
Any thoughts where to start?
int convertCMSampleBufferToPixelArray (CMSampleBufferRef sampleBuffer)
{
// inputs
CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
CIImage *ciImage = [CIImage imageWithCVPixelBuffer:imageBuffer];
CIContext *imgContext = [CIContext new];
CGImageRef cgImage = [imgContext createCGImage:ciImage fromRect:ciImage.extent];
UIImage *uiImage = [UIImage imageWithCGImage:cgImage];
NSData *nsData = UIImagePNGRepresentation(uiImage);
// Need to fill this gap
uint8_t* data = XXXXXXXXXXXXXXXX;
ImageFormat format = XXXXXXXXXXXXXXXX; // one of: GRAY8, RGB_888, YV12, BGRA_8888, ARGB_8888
// sample showing expected data values
// this routine converts the image data to gray
//
int width = uiImage.size.width;
int height = uiImage.size.height;
const int size = width * height;
std::unique_ptr<uint8_t[]> new_data(new uint8_t[size]);
for (int i = 0; i < size; ++i) {
new_data[i] = uint8_t(data[i * 3] * 0.299f + data[i * 3 + 1] * 0.587f +
data[i * 3 + 2] * 0.114f + 0.5f);
}
return 1;
}
Some pointers you can use to search for more info. It's nicely documented and you shouldn't have an issue.
int convertCMSampleBufferToPixelArray (CMSampleBufferRef sampleBuffer) {
CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
if (imageBuffer == NULL) {
return -1;
}
// Get address of the image buffer
CVPixelBufferLockBaseAddress(imageBuffer, 0);
uint8_t* data = CVPixelBufferGetBaseAddress(imageBuffer);
// Get size
size_t width = CVPixelBufferGetWidth(imageBuffer);
size_t height = CVPixelBufferGetHeight(imageBuffer);
// Get bytes per row
size_t bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer);
// At `data` you have a bytesPerRow * height bytes of the image data
// To get pixel info you can call CVPixelBufferGetPixelFormatType, ...
// you can call CVImageBufferGetColorSpace and inspect it, ...
// When you're done, unlock the base address
CVPixelBufferUnlockBaseAddress(imageBuffer, 0);
return 0;
}
There're couple of things you should be aware of.
First one is that it can be planar. Check the CVPixelBufferIsPlanar, CVPixelBufferGetPlaneCount, CVPixelBufferGetBytesPerRowOfPlane, etc.
Second one is that you have to calculate pixel size based on CVPixelBufferGetPixelFormatType. Something like:
CVPixelBufferGetPixelFormatType(imageBuffer)
size_t pixelSize;
switch (pixelFormat) {
case kCVPixelFormatType_32BGRA:
case kCVPixelFormatType_32ARGB:
case kCVPixelFormatType_32ABGR:
case kCVPixelFormatType_32RGBA:
pixelSize = 4;
break;
// + other cases
}
Let's say that the buffer is not planar and:
CVPixelBufferGetWidth returns 200 (pixels)
Your pixelSize is 4 (calcuated bytes per row is 200 * 4 = 800)
CVPixelBufferGetBytesPerRow can return anything >= 800
In other words, the pointer you have is not a pointer to a contiguous buffer. If you need row data you have to do something like this:
uint8_t* data = CVPixelBufferGetBaseAddress(imageBuffer);
// Get size
size_t width = CVPixelBufferGetWidth(imageBuffer);
size_t height = CVPixelBufferGetHeight(imageBuffer);
size_t pixelSize = 4; // Let's pretend it's calculated pixel size
size_t realRowSize = width * pixelSize;
size_t bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer);
for (int row = 0 ; row < height ; row++) {
// bytesPerRow acts like an offset where the next row starts
// bytesPerRow can be >= realRowSize
uint8_t *rowData = data + row * bytesPerRow;
// realRowSize = how many bytes are available for this row
// copy them somewhere
}
You have to allocate a buffer and copy these row data there if you'd like to have contiguous buffer. How many bytes to allocate? CVPixelBufferGetDataSize.
We have an old Print driver which takes a document and sends PCL to the spooler. The client then processes this PCL and displays everything as TIFF. Our users have been complaining that the TIFF is fuzzy and the image is not sharp. I am given this stupid task of solving the mystery
Is the PCL itself bad. I don't have enough knowledge about a PCL and if it has resolution. How do I trap the output of a driver that's being sent to the spooler?
Or is it the client that is somehow not rendering the PCL with a good resolution. Do I need to go through the pain of learning how to debug this driver. I will but is it going to help me fix a resolution issue. I have never done driver development so its going to be a curve for me. But if I need to do then thats ok. Where should I start? Is the PCL thats bad or the client that converts PCL to bitmap bad?
This is the C++ code
BOOL APIENTRY
CreatePCLRasterGraphicPage(
SURFOBJ *pso,
BOOL firstPage,
char *pageText
)
/*++
Routine Description:
Creates standard PCL end-of-document lines.
Arguments:
SURFOBJ - Surface Object
BOOL - First Page ?
char * Page Text
Return Value:
BOOL - True if successful
--*/
{
PDEVOBJ pDevObj = (PDEVOBJ)pso->dhpdev;
POEMPDEV pOemPDEV = (POEMPDEV)pDevObj->pdevOEM;
DWORD dwOffset = 0;
DWORD dwWritten = 0;
DWORD dwPageBufferSize = 0;
int i = 0;
ULONG n = 0;
BYTE bitmapRow[1050];
BYTE compRow[2100];
DWORD dwRowSize = 0;
DWORD dwCompPCLBitmapSize = 0;
//wchar_t traceBuff[256];
pOemPDEV->dwCompBitmapBufSize = 0;
// TRACE OUT ----------------------------------------------------
//ZeroMemory(traceBuff, 256);
//StringCchPrintf(traceBuff, 256, L"Top of CreatePCLRasterGraphicPage");
//WriteTraceLine(traceBuff);
// -----------------------------------------------------------------
// Invert color
for (n = 0; n < pso->cjBits; n++)
*(((PBYTE &)pso->pvBits) + n) ^= 0xFF;
// compress each row and store in a buffer with PCL line headings
for (i = 0; i < pso->sizlBitmap.cy; i++) {
// Zero Memory hack for bottom of form black line
if (*(((PBYTE &)pso->pvScan0) + (i * pso->lDelta) + 319) == 0xFF)
ZeroMemory(((PBYTE &)pso->pvScan0) + (i * pso->lDelta), 320);
// Copy the bitmap scan line into bitmapRow and send them off to be compressed
ZeroMemory(bitmapRow, 1050);
ZeroMemory(compRow, 2100);
MoveMemory(bitmapRow, ((PBYTE &)pso->pvScan0) + (i * pso->lDelta), pso->lDelta);
dwRowSize = CompressBitmapRow(compRow, bitmapRow, pso->lDelta);
// Create PCL Row Heading
char bufPCLLineHead[9];
StringCchPrintfA(bufPCLLineHead, 9, "%c%s%d%s", 27, "*b", dwRowSize, "W");
if ((dwCompPCLBitmapSize + dwRowSize + strlen(bufPCLLineHead))
> pOemPDEV->dwCompBitmapBufSize) {
if (!GrowCompBitmapBuf(pOemPDEV)) {
//ZeroMemory(traceBuff, 256);
//StringCchPrintf(traceBuff, 256,
// L"Compressed bitmap buffer could not allocate more memory.");
//WriteTraceLine(traceBuff);
}
}
if (pOemPDEV->pCompBitmapBufStart) {
// write the PCL line heading to the buffer
MoveMemory(pOemPDEV->pCompBitmapBufStart + dwCompPCLBitmapSize,
bufPCLLineHead, strlen(bufPCLLineHead));
dwCompPCLBitmapSize += strlen(bufPCLLineHead);
// write the compressed row to the buffer
MoveMemory(pOemPDEV->pCompBitmapBufStart + dwCompPCLBitmapSize,
compRow, dwRowSize);
dwCompPCLBitmapSize += dwRowSize;
}
}
// Calculate size and create buffer
dwPageBufferSize = 21;
if (!firstPage)
dwPageBufferSize++;
bGrowBuffer(pOemPDEV, dwPageBufferSize);
// Add all Raster Header Lines
if (!firstPage)
{
// Add a Form Feed
char bufFormFeed[2];
StringCchPrintfA(bufFormFeed, 2, "%c", 12); // 1 char
MoveMemory(pOemPDEV->pBufStart + dwOffset, bufFormFeed, 2);
dwOffset += 1;
}
// Position cursor at X0, Y0
char bufXY[8];
StringCchPrintfA(bufXY, 8, "%c%s", 27, "*p0x0Y"); // 7 chars
MoveMemory(pOemPDEV->pBufStart + dwOffset, bufXY, 8);
dwOffset += 7;
// Start Raster Graphics
char bufStartRas[6];
StringCchPrintfA(bufStartRas, 6, "%c%s", 27, "*r1A"); // 5 chars
MoveMemory(pOemPDEV->pBufStart + dwOffset, bufStartRas, 6);
dwOffset += 5;
// Raster Encoding - Run-Length Encoding
char bufRasEncoding[6];
StringCchPrintfA(bufRasEncoding, 6, "%c%s", 27, "*b1M"); // 5 chars
MoveMemory(pOemPDEV->pBufStart + dwOffset, bufRasEncoding, 6);
dwOffset += 5;
// Write out bitmap header PCL
dwWritten = pDevObj->pDrvProcs->DrvWriteSpoolBuf(pDevObj, pOemPDEV->pBufStart, dwPageBufferSize);
// Write out PCL plus compressed bitmap bytes
dwWritten = pDevObj->pDrvProcs->DrvWriteSpoolBuf(pDevObj, pOemPDEV->pCompBitmapBufStart, dwCompPCLBitmapSize);
// End Raster Graphics
char bufEndRas[5];
StringCchPrintfA(bufEndRas, 5, "%c%s", 27, "*rB"); // 4 chars
MoveMemory(pOemPDEV->pBufStart + dwOffset, bufEndRas, 5);
// Write out PCL end bitmap
dwWritten = pDevObj->pDrvProcs->DrvWriteSpoolBuf(pDevObj, bufEndRas, 4);
// Free Compressed Bitmap Memory
if (pOemPDEV->pCompBitmapBufStart) {
MemFree(pOemPDEV->pCompBitmapBufStart);
pOemPDEV->pCompBitmapBufStart = NULL;
pOemPDEV->dwCompBitmapBufSize = 0;
dwPageBufferSize = 0;
}
// Free Memory
vFreeBuffer(pOemPDEV);
// Write Page Text to the spooler
size_t charCount = 0;
StringCchLengthA(pageText, 32767, &charCount);
char bufWriteText[15];
ZeroMemory(bufWriteText, 15);
StringCchPrintfA(bufWriteText, 15, "%c%s%d%s", 27, "(r", charCount, "W");
dwWritten = pDevObj->pDrvProcs->DrvWriteSpoolBuf(pDevObj, bufWriteText, strlen(bufWriteText));
dwWritten = pDevObj->pDrvProcs->DrvWriteSpoolBuf(pDevObj, pageText, charCount);
return TRUE;
}
BOOL
GrowCompBitmapBuf(
POEMPDEV pOemPDEV
)
/*++
Routine Description:
Grows memory by 1000 bytes (per call) to hold compressed
bitmap and PCL data.
Arguments:
POEMPDEV - Pointer to the private PDEV structure
Return Value:
BOOL - True is successful
--*/
{
DWORD dwOldBufferSize = 0;
PBYTE pNewBuffer = NULL;
dwOldBufferSize = pOemPDEV->pCompBitmapBufStart ? pOemPDEV->dwCompBitmapBufSize : 0;
pOemPDEV->dwCompBitmapBufSize = dwOldBufferSize + 4096;
pNewBuffer = (PBYTE)MemAlloc(pOemPDEV->dwCompBitmapBufSize);
if (pNewBuffer == NULL) {
MemFree(pOemPDEV->pCompBitmapBufStart);
pOemPDEV->pCompBitmapBufStart = NULL;
pOemPDEV->dwCompBitmapBufSize = 0;
return FALSE;
}
if (pOemPDEV->pCompBitmapBufStart) {
CopyMemory(pNewBuffer, pOemPDEV->pCompBitmapBufStart, dwOldBufferSize);
MemFree(pOemPDEV->pCompBitmapBufStart);
pOemPDEV->pCompBitmapBufStart = pNewBuffer;
}
else {
pOemPDEV->pCompBitmapBufStart = pNewBuffer;
}
return TRUE;
}
RLE encoding (I have not had a chance to add this yet). I was looking at different forums as how the code should like and this is what I came up with. I will add, test the document and update the post
public virtual sbyte[] decompressRL(sbyte[] data, int startOffset, int width, int count)
{
/*type 1 compression*/
int dataCount = count;
List<sbyte> decompressed = new List<sbyte>();
int numberOfDecompressedBytes = 0;
int dataStartOffset = startOffset;
while (dataCount-- > 0)
{
int cntrlByte = (int) data[dataStartOffset++];
// Repeated pattern
int val = data[dataStartOffset++];
dataCount--;
while (cntrlByte >= 0)
{
decompressed.Insert(numberOfDecompressedBytes++, new sbyte?((sbyte) val));
cntrlByte--;
}
}
mMaxUncompressedByteCount = numberOfDecompressedBytes;
return getBytes(decompressed);
}
This is how fuzzy the users claim that the image looks. This is when printed from a word document to the driver. The original is very clear.
I have 2x2 image
Shouldn't the pixels be arranged like this?
1 2 // each number is a pixel
3 4
I'm having trouble accessing a pixel with x and y because
when x = 1 and y = 0 i get index 2 but prints the rgb values of pixel 4
so it's something like?
1 2 // each number is a pixel
4 3
Here's the code that I use
index = y + x * s->w;
c = s->format->palette->colors[index]; // c is an SDL_Color and s is an SDL_Surface*
I also use this for loop and still prints the same
for (Uint8 i = *(Uint8 *)s->pixels; i < s->w*s->h; i++) {
c = s->format->palette->colors[i];
printf("%u %u %u %u \n", i, c.r , c.g , c.b);
}
SDL_Surface struct definition from the SDL documentation
typedef struct SDL_Surface {
Uint32 flags; /* Read-only */
SDL_PixelFormat *format; /* Read-only */
int w, h; /* Read-only */
Uint16 pitch; /* Read-only */
void *pixels; /* Read-write */
/* clipping information */
SDL_Rect clip_rect; /* Read-only */
/* Reference count -- used when freeing surface */
int refcount; /* Read-mostly */
/* This structure also contains private fields not shown here */
} SDL_Surface;
Uint8 *pixel = (Uint8 *)s->pixels,*index;
index = &pixel[y + x * s->pitch];
c = s->format->palette->colors[*index];
Got it doing using #holyblackcat's suggestion.
i'm using the java method below to write an android.graphics.Bitmap to tga, i've opened the photo in photoshop and it's allright. in native i have to load and display this image with opengl, but the loading of image is incorrect and i see incorrect colors on the screen, the c++ tga loader is below. anybody has any ideea what's the problem?
java write tga method:
public static void writeTGA(Bitmap src, String path) throws IOException {
ByteBuffer buffer = ByteBuffer.allocate(src.getRowBytes() * src.getHeight());
src.copyPixelsToBuffer(buffer);
boolean alpha = src.hasAlpha();
byte[] data;
byte[] pixels = buffer.array();
if (pixels.length != src.getWidth() * src.getHeight() * (alpha ? 4 : 3))
throw new IllegalStateException();
data = new byte[pixels.length];
for(int i=0;i < pixels.length; i += 4){// rgba -> bgra
data[i] = pixels[i+2];
data[i+1] = pixels[i+1];
data[i+2] = pixels[i];
data[i+3] = pixels[i+3];
}
byte[] header = new byte[18];
header[2] = 2; // uncompressed, true-color image
header[12] = (byte) ((src.getWidth() >> 0) & 0xFF);
header[13] = (byte) ((src.getWidth() >> 8) & 0xFF);
header[14] = (byte) ((src.getHeight() >> 0) & 0xFF);
header[15] = (byte) ((src.getHeight() >> 8) & 0xFF);
header[16] = (byte) (alpha ? 32 : 24); // bits per pixel
header[17] = (byte) ((alpha ? 8 : 0) | (1 << 4));
File file = new File(path);
RandomAccessFile raf = new RandomAccessFile(file, "rw");
raf.write(header);
raf.write(data);
raf.setLength(raf.getFilePointer()); // trim
raf.close();
}
tga 18 bit header c++ :
typedef struct _tgaheader {
BYTE IDLength; /* 00h Size of Image ID field */
BYTE ColorMapType; /* 01h Color map type */
BYTE ImageType; /* 02h Image type code */
BYTE CMapStart[2]; /* 03h Color map origin */
BYTE CMapLength[2]; /* 05h Color map length */
BYTE CMapDepth; /* 07h Depth of color map entries */
WORD XOffset; /* 08h X origin of image */
WORD YOffset; /* 0Ah Y origin of image */
WORD Width; /* 0Ch Width of image */
WORD Height; /* 0Eh Height of image */
BYTE PixelDepth; /* 10h Image pixel size */
BYTE ImageDescriptor; /* 11h Image descriptor byte */
} TGAHEADER;
tga loader method:
void TgaFormat:: LoadImage(const char *path) {
FILE* filePtr = fopen(path, "rb");
long imageSize;
short pixel_size;
unsigned char colorSwap;
// Open the TGA file.
if( filePtr == NULL){
LOGI("cannot find Tga File!");
return;
}
fread(&file_header, 1, sizeof(TGAHEADER), filePtr);
short sz = sizeof(TGAHEADER);
// 2 (uncompressed RGB image), 3 (uncompressed black-and-white images).
if (file_header.ImageType != 2 ){
fclose(filePtr);
LOGI("this file is not a TGA!");
return;
}
// Color mode -> 3 = BGR, 4 = BGRA.
pixel_size = file_header.PixelDepth / 8;
imageSize = file_header.Width * file_header.Height * pixel_size;
m_rgba_data = (BYTE* )malloc( sizeof(BYTE) * imageSize );
if( fread(m_rgba_data, 1, imageSize, filePtr) != imageSize ) {
fclose(filePtr);
return ;
}
fclose(filePtr);
// Change from BGRA to RGBA so OpenGL can read the image data.
for (int imageIdx = 0; imageIdx < imageSize; imageIdx += pixel_size) {
colorSwap = m_rgba_data[imageIdx];
m_rgba_data[imageIdx] = m_rgba_data[imageIdx + 2];
m_rgba_data[imageIdx + 2] = colorSwap;
}
}
after reading the tga file in android native and rendered with opengles
the generated qr code into sdcard the opened with photoshop
the second photo was writed in java, then open in photoshop. i found the mistake. as i was been thinking, i've got a wrong offset, but not in writing/reading process.
into the upload to gpu:
I had
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB.....);
instead of
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA....);
because my pixel size is 4 (RGBA) not 3 (RGB).
I would like to update an AV Audio encoder using function avcodec_encode_audio (deprecated) to avcodec_encode_audio2, without modifying the structure of existing encoder:
outBytes = avcodec_encode_audio(m_handle, dst, sizeBytes, (const short int*)m_samBuf);
where:
1) m_handle AVCodecContext
2) dst, uint8_t * destination buffer
3) sizeBytes, uint32_t size of the destination buffer
4) m_samBuf void * to the input chunk of data to encode (this is casted to: const short int*)
is there a simply way to do it?
Im tryng with:
int gotPack = 1;
memset (&m_Packet, 0, sizeof (m_Packet));
m_Frame = av_frame_alloc();
av_init_packet(&m_Packet);
m_Packet.data = dst;
m_Packet.size = sizeBytes;
uint8_t* buffer = (uint8_t*)m_samBuf;
m_Frame->nb_samples = m_handle->frame_size;
avcodec_fill_audio_frame(m_Frame,m_handle->channels,m_handle->sample_fmt,buffer,m_FrameSize,1);
outBytes = avcodec_encode_audio2(m_handle, &m_Packet, m_Frame, &gotPack);
char error[256];
av_strerror(outBytes,error,256);
if (outBytes<0){
m_server->log(1,1,"Input data: %d, encode function call error: %s \n",gotPack, error);
return AUDIOWRAPPER_ERROR;
}
av_frame_free(&m_Frame);
it compiles but it does not encode anything, i dont here audio at the output if I pipe the output stream on mplayer, wich was warking prior to the upgrade.
What am I doing wrong?
The encoder accept only two sample formats:
AV_SAMPLE_FMT_S16, ///< signed 16 bits
AV_SAMPLE_FMT_FLT, ///< float
here is how the buffer is allocated:
free(m_samBuf);
int bps = 2;
if(m_handle->codec->sample_fmts[0] == AV_SAMPLE_FMT_FLT) {
bps = 4;
}
m_FrameSize = bps * m_handle->frame_size * m_handle->channels;
m_samBuf = malloc(m_FrameSize);
m_numSam = 0;
avcodec_fill_audio_frame should get you there
memset (&m_Packet, 0, sizeof (m_Packet));
memset (&m_Frame, 0, sizeof (m_Frame));
av_init_packet(&m_Packet);
m_Packet.data = dst;
m_Packet.size = sizeBytes;
m_Frame->nb_samples = //you need to get this value from somewhere, it is the number of samples (per channel) this frame represents
avcodec_fill_audio_frame(m_Frame, m_handle->channels, m_handle->sample_fmt,
buffer,
sizeBytes, 1);
int gotPack = 1;
avcodec_encode_audio2(m_handle, &m_Packet, &m_Frame, &gotPack);