/* LodePNG Translucent Border Generator Copyright (c) 2005-2007 Lode Vandevenne This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. */ /* This program can be used to give a PNG a translucent border that can look nice on webpages. -In Seamonkey, Firefox, Opera and Internet Explorer 7 the border is translucent against the background. -In Internet Explorer 6, the background color in the PNG is shown through the image. Therefor, to make it look good on webpages in IE6 too, you can specify the background color to store in the PNG (which should match the background of the webpage) -You can, if you compile this with SDL, also view the image you generated, against its background color, with this program. */ //g++ *.cpp -lSDL -O3 -W -Wall -Wextra -pedantic -ansi #include #include #include #include "lodepng.h" #define ENABLE_SDL //undefine this if you can't compile stuff that uses SDL //////////////////////////////////////////////////////////////////////////////// int border(const std::string& filename_in, const std::string& filename_out, int r, int g, int b, int bordersize) { std::vector image; unsigned w, h; int error = LodePNG::decode(image, w, h, filename_in); if(error) { std::cout << "error: " << error << std::endl; return 0; } const float border = bordersize; const unsigned long cx0 = (unsigned long)border * 2; const unsigned long cx1 = w - ((unsigned long)border * 2) - 1; const unsigned long cy0 = (unsigned long)border * 2; const unsigned long cy1 = h - ((unsigned long)border * 2) - 1; //ghostify image for(size_t y = 0; y < h; y++) for(size_t x = 0; x < w; x++) { bool corner00 = x < cx0 && y < cy0; bool corner01 = x < cx0 && y > cy1; bool corner10 = x > cx1 && y < cy0; bool corner11 = x > cx1 && y > cy1; bool top = y < border && !corner00 && !corner10; bool right = x > w - border && !corner10 && !corner11; bool bottom = y > h - border && !corner01 && !corner11; bool left = x < border && !corner00 && !corner01; float alpha = 1.0; if(corner00) { float distance = (std::sqrt((x - cx0) * (x - cx0) + (y - cy0) * (y - cy0))) / border - 1.0; if(distance < 0) distance = 0; if(distance > 1) distance = 1; alpha = (1.0 - distance); } else if(corner01) { float distance = (std::sqrt((x - cx0) * (x - cx0) + (y - cy1) * (y - cy1))) / border - 1.0; if(distance < 0) distance = 0; if(distance > 1) distance = 1; alpha = (1.0 - distance); } else if(corner10) { float distance = (std::sqrt((x - cx1) * (x - cx1) + (y - cy0) * (y - cy0))) / border - 1.0; if(distance < 0) distance = 0; if(distance > 1) distance = 1; alpha = (1.0 - distance); } else if(corner11) { float distance = (std::sqrt((x - cx1) * (x - cx1) + (y - cy1) * (y - cy1))) / border - 1.0; if(distance < 0) distance = 0; if(distance > 1) distance = 1; alpha = (1.0 - distance); } else if(top) alpha = y / border; else if(bottom) alpha = (h - y - 1) / border; else if(left) alpha = x / border; else if(right) alpha = (w - x - 1) / border; size_t index = 4 * w * y + 4 * x; image[index + 3] = (unsigned char)(alpha * 255); } LodePNG::Encoder encoder; encoder.getInfoPng().background_defined = true; encoder.getInfoPng().background_r = r; encoder.getInfoPng().background_g = g; encoder.getInfoPng().background_b = b; std::vector buffer; encoder.encode(buffer, image, w, h); LodePNG::saveFile(buffer, filename_out); return 0; } //////////////////////////////////////////////////////////////////////////////// #ifdef ENABLE_SDL #include //requires SDL int show(const std::string& filename) { std::vector buffer, image; LodePNG::loadFile(buffer, filename); //load the image file with given filename LodePNG::Decoder decoder; decoder.decode(image, buffer); //decode the png //get width, height and pixels unsigned w = decoder.getWidth(), h = decoder.getHeight(); //stop if there is an error if(decoder.hasError()) { std::cout << "error: " << decoder.getError() << std::endl; return 0; } Uint32 bgr = decoder.getInfoPng().background_r; Uint32 bgg = decoder.getInfoPng().background_g; Uint32 bgb = decoder.getInfoPng().background_b; //avoid too large window size by downscaling large image unsigned long jump = 1; if(w / 1024 >= jump) jump = w / 1024 + 1; if(h / 1024 >= jump) jump = h / 1024 + 1; //init SDL if(SDL_Init(SDL_INIT_VIDEO) < 0) return 0; SDL_Surface* scr = SDL_SetVideoMode(w / jump, h / jump, 32, SDL_HWSURFACE); if(!scr) return 0; SDL_WM_SetCaption(filename.c_str(), NULL); //set window caption //plot the pixels of the PNG file for(unsigned long y = 0; y + jump - 1 < h; y += jump) for(unsigned long x = 0; x + jump - 1 < w; x += jump) { //get RGBA components Uint32 r = image[4 * y * w + 4 * x + 0]; //red Uint32 g = image[4 * y * w + 4 * x + 1]; //green Uint32 b = image[4 * y * w + 4 * x + 2]; //blue Uint32 a = image[4 * y * w + 4 * x + 3]; //alpha //make translucency visible by placing checkerboard pattern behind image r = (a * r + (255 - a) * bgr) / 255; g = (a * g + (255 - a) * bgg) / 255; b = (a * b + (255 - a) * bgb) / 255; //give the color value to the pixel of the screenbuffer Uint32* bufp; bufp = (Uint32 *)scr->pixels + (y * scr->pitch / 4) / jump + (x / jump); *bufp = 65536 * r + 256 * g + b; } //pause until you press escape and meanwhile redraw screen SDL_Event event; int done = 0; while(done == 0) { while(SDL_PollEvent(&event)) { if(event.type == SDL_QUIT) done = 1; if(SDL_GetKeyState(NULL)[SDLK_ESCAPE]) done = 1; } SDL_UpdateRect(scr, 0, 0, 0, 0); //redraw screen SDL_Delay(5); //pause 5 ms so it consumes less processing power } SDL_Quit(); return 0; } #endif //////////////////////////////////////////////////////////////////////////////// int main(int argc, char *argv[]) { bool correct_args = true; if(argc < 2) correct_args = false; int mode = -1; if(correct_args) { std::string param1(argv[1]); if(param1 == "-b") mode = 0; //generate border else if(param1 == "-s") mode = 1; //show else correct_args = false; if(mode == 0 && (argc != 7 && argc != 8)) correct_args = false; if(mode == 1 && argc != 3) correct_args = false; } if(!correct_args) { std::cout << "\ Incorrect parameters specified, so here's the manual:\n\ \n\ This program can give a PNG a translucent border that looks nice on webpages.\n\ -In Konqueror, Firefox & co, Opera and IE 7 the border is translucent against the background.\n\ -In IE 6, the bgcolor in the PNG is shown through the image. So, to make it look acceptable\n\ in IE6 too, you can specify the bgcolor to store in the PNG (which should match the background of the webpage)\n\ -You can, if you compile this with SDL, also view the image you generated, against its bgcolor\n\ \n\ usage:\n\ *) to generate border, use the following parameters:\n\ -b R G B bordersize image_in.png (image_out.png)\n\ R, G and B are values from 0-255 representing background color\n\ bordersize is an integer representing the size of the border\n\ If no image_out filename given, THIS OVERWRITES THE ORIGINAL IMAGE!\n\ *) to view image against its background color:\n\ -s image.png \n\ This only works if this executable was compiled with SDL" << std::endl; return 0; } if(mode == 0) { std::string filename_in = argv[6]; std::string filename_out = argc > 7 ? argv[7] : argv[6]; int r, g, b, bordersize; std::stringstream s; s << argv[2]; s >> r; s.clear(); s << argv[3]; s >> g; s.clear(); s << argv[4]; s >> b; s.clear(); s << argv[5]; s >> bordersize; return border(filename_in, filename_out, r, g, b, bordersize); } #ifdef ENABLE_SDL if(mode == 1) { std::string filename = argv[2]; return show(filename); } #endif }