void Image::PrintInfo() const { float avg[4] = {0, 0, 0, 0}; auto f = PixelAt(0, 0); float max[4] = {f.r, f.g, f.b, f.a}; float min[4] = {f.r, f.g, f.b, f.a}; for (int y = 0; y < m_Size.y; y++) { for (int x = 0; x < m_Size.x; x++) { auto col = PixelAt(x, y); float r = col.r; float g = col.g; float b = col.b; float a = col.a; avg[0] += r; avg[1] += g; avg[2] += b; avg[3] += a; max[0] = std::max(max[0], r); max[1] = std::max(max[1], g); max[2] = std::max(max[2], b); max[3] = std::max(max[3], a); min[0] = std::min(min[0], r); min[1] = std::min(min[1], g); min[2] = std::min(min[2], b); min[3] = std::min(min[3], a); } } assert( static_cast<unsigned>(m_Size.x * m_Size.y ) == m_Data.size()); const size_t total = m_Size.x * m_Size.y; parallel_printf(" Image %dx%d, \n avg {%f,%f,%f,%f} \n min {%f,%f,%f,%f} " "\n max {%f,%f,%f,%f} \n", m_Size.x, m_Size.y, avg[0] / total, avg[1] / total, avg[2] / total, avg[3] / total, min[0], min[1], min[2], min[3], max[0], max[1], max[2], max[3], max[0]); }
void Image::SaveToPNG(const std::string &filename) { FILE *fp = std::fopen(filename.c_str(), "wb"); if (!fp) abort(); png_structp png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png) abort(); png_infop info = png_create_info_struct(png); if (!info) abort(); if (setjmp(png_jmpbuf(png))) abort(); png_init_io(png, fp); // Output is 8bit depth, RGBA format. png_set_IHDR(png, info, m_Size.x, m_Size.y, 8, PNG_COLOR_TYPE_RGBA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); png_write_info(png, info); // To remove the alpha channel for PNG_COLOR_TYPE_RGB format, // Use png_set_filler(). // png_set_filler(png, 0, PNG_FILLER_AFTER); std::vector<png_byte> row; row.resize(4 * m_Size.x * sizeof(png_byte)); // Write image data for (int y = 0; y < m_Size.y; y++) { for (int x = 0; x < m_Size.x; x++) { auto col = PixelAt(x, y); float r = col.r * 255; float g = col.g * 255; float b = col.b * 255; float a = col.a * 255; if (r > 255) r = 255; if (g > 255) g = 255; if (b > 255) b = 255; if (a > 255) a = 255; row[x * 4] = static_cast<char>(r); row[x * 4 + 1] = static_cast<char>(g); row[x * 4 + 2] = static_cast<char>(b); row[x * 4 + 3] = static_cast<char>(a); } png_write_row(png, row.data()); } // End write png_write_end(png, NULL); fclose(fp); }
ALERROR rgnCreateFromBitmap (HBITMAP hBitmap, HRGN *rethRgn) // rgnCreateFromBitmap // // Creates a region from a bitmap { ALERROR error; HDC hDC = NULL; DWORD *pLine = NULL; RGNDATAHEADER rdh; BITMAP bm; int x, y; int iLineSize; char bitmapinfo[sizeof(BITMAPINFOHEADER) + 2 * sizeof(DWORD)]; BITMAPINFOHEADER *pbmi = (BITMAPINFOHEADER *)bitmapinfo; // Figure out the size of the bitmap GetObject(hBitmap, sizeof(bm), &bm); // Prepare an output stream CMemoryWriteStream Output(bm.bmWidth * bm.bmHeight * sizeof(RECT)); if (error = Output.Create()) goto Fail; rdh.dwSize = sizeof(rdh); rdh.iType = RDH_RECTANGLES; rdh.nCount = 0; rdh.nRgnSize = 0; // We assume that the bitmap already represents the bounding rect rdh.rcBound.top = 0; rdh.rcBound.left = 0; rdh.rcBound.bottom = bm.bmHeight; rdh.rcBound.right = bm.bmWidth; // Write out the unitialized header; we will fill it in later if (error = Output.Write((char *)&rdh, sizeof(rdh), NULL)) goto Fail; // Prepare hDC = CreateCompatibleDC(NULL); iLineSize = AlignUp(bm.bmWidth, 32) / 32; pLine = (DWORD *)MemAlloc(iLineSize * sizeof(DWORD)); ZeroMemory(pbmi, sizeof(BITMAPINFOHEADER)); pbmi->biSize = sizeof(BITMAPINFOHEADER); pbmi->biWidth = bm.bmWidth; pbmi->biHeight = bm.bmHeight; pbmi->biPlanes = 1; pbmi->biBitCount = 1; pbmi->biCompression = BI_RGB; // Loop over each scan line for (y = 0; y < bm.bmHeight; y++) { int xRunStart; GetDIBits(hDC, hBitmap, y, 1, pLine, (BITMAPINFO *)pbmi, DIB_RGB_COLORS); // Look for the beginning of a run x = 0; xRunStart = -1; while (x < bm.bmWidth) { if (xRunStart == -1) { // If we're not in a run and we suddenly find a white pixel // then we know that we begin a run if (PixelAt(pLine, x)) xRunStart = x; } else { // If we're in a run and we suddenly find a black pixel // then we know that we're done if (!PixelAt(pLine, x)) { RECT rcRect; rcRect.left = xRunStart; rcRect.top = y; rcRect.right = x; rcRect.bottom = y + 1; // Add the rect to the region if (error = Output.Write((char *)&rcRect, sizeof(rcRect), NULL)) goto Fail; rdh.nCount++; rdh.nRgnSize += sizeof(RECT); xRunStart = -1; } } x++; } // If we were in a run, then end it if (xRunStart != -1) { RECT rcRect; rcRect.left = xRunStart; rcRect.top = y; rcRect.right = x; rcRect.bottom = y + 1; // Add the rect to the region if (error = Output.Write((char *)&rcRect, sizeof(rcRect), NULL)) goto Fail; rdh.nCount++; rdh.nRgnSize += sizeof(RECT); } } // Close it out MemFree(pLine); pLine = NULL; DeleteDC(hDC); hDC = NULL; if (error = Output.Close()) goto Fail; // Update the header *(RGNDATAHEADER *)Output.GetPointer() = rdh; // Create the region *rethRgn = ExtCreateRegion(NULL, Output.GetLength(), (RGNDATA *)Output.GetPointer()); // Done return NOERROR; Fail: if (pLine) MemFree(pLine); if (hDC) DeleteDC(hDC); return error; }