int CreateCompositeImage(CompositeParameters ¶ms, const char *outName) { // Try to read in all of the inputs. bool noError = true; int i; for(i = 0; i < params.nViewports && noError; ++i) { params.viewports[i]->file = new ImageObject; noError = params.viewports[i]->file->Read( params.viewports[i]->imageName); } if(!noError) { fprintf(stderr, "The following files could not be read:\n"); for(i = 0; i < params.nViewports; ++i) fprintf(stderr, "\t%s\n", params.viewports[i]->imageName); return -3; } int startViewport = 0; ImageObject *output = 0; int width, height; if(strcmp(params.backgroundFile, params.viewports[0]->imageName) == 0) { startViewport = 1; width = params.viewports[0]->file->Width(); height = params.viewports[0]->file->Height(); output = params.viewports[0]->file; } else { width = params.outputSize[0]; height = params.outputSize[1]; output = new ImageObject(width, height); // Set the image's background color. unsigned char *cptr = output->Pixel(0,0); unsigned int sz = width * height; for(unsigned int s = 0; s < sz; ++s) { *cptr++ = params.outputBackground[0]; *cptr++ = params.outputBackground[1]; *cptr++ = params.outputBackground[2]; } } // Calculate some shadow parameters based on the image size. int offx = int(params.shadowOffsetX * width); int offy = int(params.shadowOffsetY * height); if (offx > offy) offy = offx; else offx = offy; int blurRad = int(params.shadowBlurRadius * width); // Now that we have all of the images in memory and we've decided // which one is the background image, we should begin compositing. for(i = startViewport; i < params.nViewports; ++i) { int start_x = int(params.viewports[i]->coordinates[0] * width); int start_y = int(height - params.viewports[i]->coordinates[1] * height); int img_w = params.viewports[i]->file->Width(); int img_h = params.viewports[i]->file->Height(); if(params.viewports[i]->hasDropShadow) { ImageObject *mask = CreateDropShadowMask(params.viewports[i], offx, offy, blurRad); if(mask != 0) { // Now that we have a drop shadow mask, let's use it to blend // the destination pixels with black. Values in the mask that // are white should be more black in the destination image. // Of course, we should limit the amount of black that we can // make a shadow. for(int masky = 0; masky < mask->Height(); ++masky) { int real_y = start_y - img_h + masky; for(int maskx = 0; maskx < mask->Width(); ++maskx) { int real_x = start_x + maskx; if(real_x >= 0 && real_x < width && real_y >= 0 && real_y < height) { unsigned char *mask_value = mask->Pixel(maskx, masky); unsigned char *dest = output->Pixel(real_x, real_y); float t = (float(*mask_value) / 255.f) * 0.5; float r = float(dest[0]); float g = float(dest[1]); float b = float(dest[2]); float new_r = (1. - t) * r + t * 0.2; float new_g = (1. - t) * g + t * 0.2; float new_b = (1. - t) * b + t * 0.2; dest[0] = (unsigned char)((int)(new_r)); dest[1] = (unsigned char)((int)(new_g)); dest[2] = (unsigned char)((int)(new_b)); } } } delete mask; } } // Now that we've drawn a drop shadow, if needed, draw the image. if(params.viewports[i]->opaqueMode == M_OPAQUE) { for(int y = 0; y < img_h; ++y) { int real_y = start_y - img_h + y; for(int x = 0; x < img_w; ++x) { int real_x = start_x + x; if(real_x >= 0 && real_x < width && real_y >= 0 && real_y < height) { unsigned char *src = params.viewports[i]->file->Pixel(x, y); unsigned char *dest = output->Pixel(real_x, real_y); *dest++ = *src++; *dest++ = *src++; *dest = *src; } } } } else if(params.viewports[i]->opaqueMode == M_TRANSPARENT) { for(int y = 0; y < img_h; ++y) { int real_y = start_y - img_h + y; for(int x = 0; x < img_w; ++x) { int real_x = start_x + x; if(real_x >= 0 && real_x < width && real_y >= 0 && real_y < height) { unsigned char *src = params.viewports[i]->file->Pixel(x, y); unsigned char *dest = output->Pixel(real_x, real_y); float dest_r = float(dest[0]); float dest_g = float(dest[1]); float dest_b = float(dest[2]); float src_r = float(src[0]); float src_g = float(src[1]); float src_b = float(src[2]); float t = params.viewports[i]->opacity; float r = (1. - t) * dest_r + t * src_r; float g = (1. - t) * dest_g + t * src_g; float b = (1. - t) * dest_b + t * src_b; *dest++ = (unsigned char)((int)r); *dest++ = (unsigned char)((int)g); *dest++ = (unsigned char)((int)b); } } } } else if(params.viewports[i]->opaqueMode == M_COLORREPLACE) { unsigned char rr, rg, rb; rr = params.viewports[i]->transparentColor[0]; rg = params.viewports[i]->transparentColor[1]; rb = params.viewports[i]->transparentColor[2]; for(int y = 0; y < img_h; ++y) { int real_y = start_y - img_h + y; for(int x = 0; x < img_w; ++x) { int real_x = start_x + x; if(real_x >= 0 && real_x < width && real_y >= 0 && real_y < height) { unsigned char *src = params.viewports[i]->file->Pixel(x, y); unsigned char *dest = output->Pixel(real_x, real_y); if(src[0] != rr || src[1] != rg || src[2] != rb) { *dest++ = *src++; *dest++ = *src++; *dest = *src; } } } } } } // Write the output image. output->Write(outName); if(startViewport == 0) delete output; return 0; }