How to overlay an image over another in P3D - image

In processing.js, how would you overlay an image over another one in P3D mode?
Here is my code:
/* #pjs preload="duck.jpg"; */
/* #pjs preload="a.png"; */
PImage imageDuck;
PImage imageA;
void setup() {
size(500, 500, P3D);
imageDuck = loadImage("duck.jpg");
imageA = loadImage("a.png");
}
void draw() {
background(255);
noStroke();
image(imageDuck, 0, 0);
image(imageA, 0, 0);
}
So what the code trying to do is to display a duck image, then overlay another image name a.png (with transparent background) on top of it.
When I use the normal size(500, 500); without the P3D mode, the image overlay works perfectly.
However, I am using P3D because the next thing I am going to do is to rotate my images together.
So in this size(500, 500, P3D) mode, I can see my a.png flashed once, then only my duck image shows. If I comment out duck, a.png will show. If I comment out a.png, my duck shows. If I reorder the image() call, still only the duck image shows. I added translate(0,0,-1) or translate(0,0,1) in between my image() calls, no luck, only my duck image shows.
Is this even possible?

I resolved my problem, it is the first line #pjs, can only be called once. Multiple images will have to be preloaded within one single line. In my example, my first 2 lines will have to be combined like such:
/* #pjs preload="duck.jpg,a.png"; */

Related

How can put image back of paints which i drew?

The thing what I want to make is similar to paint program.
The problem is when I draw some lines(Not just lines. Whole things I drew are included in this case.), those lines only drawn back of a image I put in before I draw that.
At first, I thought it was just problem of code's order. But it wasn't.
I just want draw some lines on the image like paint program.
Like this:enter image description here
You can paint into a separate "layer" using PGraphics.
Once you initialise an instance you can use the typical drawing methods within beginDraw() / endDraw() (as the reference example suggests).
The only thing left is to save the final image which is simple enough using save()
Here's a modified example of Examples > Basics > Image > LoadDisplay which uses a separate PGraphics instance to draw into as the mouse is dragged and saves the final image when the s key is pressed:
/**
* Based on Examples > Basics > Image > Load and Display
*
* Images can be loaded and displayed to the screen at their actual size
* or any other size.
*/
PImage img; // Declare variable "a" of type PImage
// reference to layer to draw into
PGraphics paintLayer;
void setup() {
size(640, 360);
// The image file must be in the data folder of the current sketch
// to load successfully
img = loadImage("moonwalk.jpg"); // Load the image into the program
// create a separate layer to draw into
paintLayer = createGraphics(width,height);
}
void draw() {
// Displays the image at its actual size at point (0,0)
image(img, 0, 0);
// Displays the paint layer
image(paintLayer,0,0);
}
void mouseDragged(){
// use drawing commands between beginDraw() / endDraw() calls
paintLayer.beginDraw();
paintLayer.line(mouseX,mouseY,pmouseX,pmouseY);
paintLayer.endDraw();
}
void keyPressed(){
if(key == 's'){
saveFrame("annotated-image.png");
}
}

How can I clear the canvas using one click in processing?

I was trying to make a very simple game but I'm having trouble with mouse events. I want to only click once and the whole canvas will be cleared but what happen is it keeps on coming back to its original canvas if I'm not clicking anymore.
if((mouseX >= 100) && (mouseX <= 235) &&
(mouseY >= 490) && (mouseY <= 540) &&
(mousePressed))
{
clear ();
slide1 ();
}
This is the second tab:
void slide1()
{
clear ();
background (30);`enter code here`
slide1 = loadImage ("slide1.jpg");
image (slide1,100,0,400,300);
}
Without seeing a complete, working example, it is difficult to tell for certain. However, it seems likely that you have confused clear() and background(). The easiest way to wipe the screen is by calling background() -- for example at the beginning of every draw() frame.
From the Processing reference:
clear(): "Clears the pixels within a buffer. This function only works on PGraphics objects"
background(): "This function is typically used within draw() to clear the display window at the beginning of each frame, but it can be used inside setup() to set the background on the first frame of animation or if the backgound need only be set once."
e.g. (based on your code):
PImage slide1;
void setup(){
size(512,512);
slide1 = loadImage ("https://processing.org/img/processing3-logo.png");
}
void draw(){
background (30); // clear screen every frame
if(mousePressed) { // show image whenever mouse is down
image (slide1,0,0);
}
}
This always clears the canvas.
Alternately, if you only want to wipe the canvas on a click, don't call background each draw -- instead, call background only on mousePressed. However, in your case (showing an image) it looks like you might also want to wipe again on mouseReleased (so that the image disappears). You may wish to use the built-in mousePressed() and mouseReleased() Processing functions for this and call background in each one.
I don't think this is what you actually want, but: the actual answer to the title question ("How can I clear the canvas using one click in processing?") is:
void draw(){
line(mouseX,mouseY,pmouseX,pmouseY);
}
void mouseClicked(){
background(192);
}

Eliminating View Angles in Processing

I'm working on a Quad-copter and for testing purposes I have decided to use Processing to give me a visual example of what the micro-controller is processing and calculating (and possibly some control algorithm simulation later on). So I have made a simple model of a Quad-copter and was displaying it in the upper right of my screen. In the "rest position," I want a perfect side view of the Quad-copter, like this:
Instead, I get an image like this:
The second image was when I rendered the Quad in the upper right, and the first is when I rendered it dead center in the window.
I understand what is happening here but I don't know how to fix it. The rendering system assumes my point of view is dead center in the screen, so anything up and to the right of my point of view is seen from underneath and in the front a little. I poked around on the Reference tab on their website and nothing seems to do exactly what I want. I would think that there would be a solution to this, but I currently can't find one.Does anyone know how to fix this? Thanks.
It sounds like you might be looking for the ortho() function. You can read about it in the reference here.
Sets an orthographic projection and defines a parallel clipping volume. All objects with the same dimension appear the same size, regardless of whether they are near or far from the camera.
Consider this little example program without calling the ortho() function:
void setup(){
size(500, 500, P3D);
}
void draw(){
background(255);
translate(300, 100);
noFill();
stroke(0);
box(100, 100, 100);
}
Now let's add the call to the ortho() function:
void setup(){
size(500, 500, P3D);
}
void draw(){
background(255);
translate(300, 100);
ortho();
noFill();
stroke(0);
box(100, 100, 100);
}
You now no longer see the "depth" of the square. You can add parameters to the ortho() function to make it do exactly what you want, but those are the basics.
Alternatively, you could do something like setup a view that you draw to the middle of, and then draw that view in the upper-right corner of your main view.

In Processing, how can I save part of the window as an image?

I am using Processing under Fedora 20, and I want to display an image of the extending tracks of objects moving across part of the screen, with each object displayed at its current position at the end of the track. To avoid having to record all the co-ordinates of the tracks, I usesave("image.png"); to save the tracks so far, then draw the objects. In the next frame I use img = loadImage("image.png"); to restore the tracks made so far, without the objects, which would still be in their previous positions.. I extend the tracks to their new positions, then usesave("image.png"); to save the extended tracks, still without the objects, ready for the next loop round. Then I draw the objects in their new positions at the end of their extended tracks. In this way successive loops show the objects advancing, with their previous positions as tracks behind them.
This has worked well in tests where the image is the whole frame, but now I need to put that display in a corner of the whole frame, and leave the rest unchanged. I expect that createImage(...) will be the answer, but I cannot find any details of how to to so.
A similar question asked here has this recommendation: "The PImage class contains a save() function that exports to file. The API should be your first stop for questions like this." Of course I've looked at that API, but I don't think it helps here, unless I have to create the image to save pixel by pixel, in which case I would expect it to slow things down a lot.
So my question is: in Processing can I save and restore just part of the frame as an image, without affecting the rest of the frame?
I have continued to research this. It seems strange to me that I can find oodles of sketch references, tutorials, and examples, that save and load the entire frame, but no easy way of saving and restoring just part of the frame as an image. I could probably do it using Pimage but that appears to require an awful lot of image. in front of everything to be drawn there.
I have got round it with a kludge: I created a mask image (see this Processing reference) the size of the whole frame. The mask is defined as grey areas representing opacity, so that white, zero opacity (0), is transparent and black, fully opaque (255) completely conceals the background image, thus:
{ size (1280,800);
background(0); // whole frame is transparent..
fill(255); // ..and..
rect(680,0,600,600); // ..smaller image area is now opaque
save("[path to sketch]/mask01.jpg");
}
void draw(){}
Then in my main code I use:
PImage img, mimg;
img = loadImage("image4.png"); // The image I want to see ..
// .. including the rest of the frame which would obscure previous work
mimg = loadImage("mask01.jpg"); // create the mask
//apply the mask, allowing previous work to show though
img.mask(mimg);
// display the masked image
image(img, 0, 0);
I will accept this as an answer if no better suggestion is made.
void setup(){
size(640, 480);
background(0);
noStroke();
fill(255);
rect(40, 150, 200, 100);
}
void draw(){
}
void mousePressed(){
PImage img =get(40, 150, 200, 100);
img.save("test.jpg");
}
Old news, but here's an answer: you can use the pixel array and math.
Let's say that this is your viewport:
You can use loadPixels(); to fill the pixels[] array with the current content of the viewport, then fish the pixels you want from this array.
In the given example, here's a way to filter the unwanted pixels:
void exportImage() {
// creating the image to the "desired size"
PImage img = createImage(600, 900, RGB);
loadPixels();
int index = 0;
for(int i=0; i<pixels.length; i++) {
// filtering the unwanted first 200 pixels on every row
// remember that the pixels[] array is 1 dimensional, so some math are unavoidable. For this simple example I use the modulo operator.
if (i % width >= 200) { // "magic numbers" are bad, remember. This is only a simplification.
img.pixels[index] = pixels[i];
index++;
}
}
img.updatePixels();
img.save("test.png");
}
It may be too late to help you, but maybe someone else will need this. Either way, have fun!

How to create an imagelist from a PNG?

I've seen here that you can create an image list with transparency. It works... sort of.
I used this to create an image list for a list control. The results were a little disappointing:
The one on the left is how it should look. The one on the right is how the list control is displaying it. It looks like it just tried to use the alpha as a mask and any blended area is attempted to be approximated by dithering. Is there a way of getting this better so that I get an actual alpha blended image?
Here is the source if that makes any difference:
class CDlg : public CDialog
{
DECLARE_DYNCREATE(CDlg)
public:
CDlg(CWnd* pParent = NULL); // standard constructor
virtual ~CDlg();
// Dialog Data
enum { IDD = IDD_BS_PRINT };
CGdiPlusBitmapResource m_pBitmap;
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
virtual BOOL OnInitDialog();
DECLARE_MESSAGE_MAP()
public:
CListCtrl m_printOptions;
};
BOOL CDlg::OnInitDialog()
{
__super::OnInitDialog();
m_pBitmap.Load(IDB_RIBBON_HOMELARGE, _T("PNG"), AfxGetResourceHandle());
HBITMAP hBitmap;
m_pBitmap.m_pBitmap->GetHBITMAP(RGB(0, 0, 0), &hBitmap);
CImageList *pList = new CImageList;
CBitmap bm;
bm.Attach(hBitmap);
pList->Create(32, 32, ILC_COLOR32, 0, 4);
pList->Add(&bm, RGB(255, 0, 255));
m_printOptions.SetImageList(pList, LVSIL_NORMAL);
//...
return TRUE;
}
IMPLEMENT_DYNCREATE(CDlg, CDialog)
CBSPrintDlg::CBSPrintDlg(CWnd* pParent /*=NULL*/)
: CBCGPDialog(CBSPrintDlg::IDD, pParent)
{
}
CBSPrintDlg::~CBSPrintDlg()
{
}
void CBSPrintDlg::DoDataExchange(CDataExchange* pDX)
{
CBCGPDialog::DoDataExchange(pDX);
DDX_Control(pDX, IDC_PRINT_OPTIONS, m_printOptions);
}
For source of CGdiPlusBitmapResource implementation look here.
The original image with transparency is this:
#Barmak tried with a different image and it looks fine. I think that is because the transparency is near the edge and not located within the image. See here:
Edit ----------
First parameter in Gdiplus::GetHBITMAP should be the background color. Using RGB(0, 0, 0) as background color causes the semi-transparent pixels to match with black.
Using Gdiplus::Color(255,255,255,255) (white) it will improve the appearance (because ListView background is also white). But it's better to change the background to Gdiplus::Color(0,255,255,255) (transparent) to match any background.
{
CGdiPlusBitmapResource gdibmp;
if (gdibmp.Load(IDB_RIBBON_HOMELARGE, _T("PNG"), AfxGetResourceHandle()))
{
HBITMAP hBitmap;
gdibmp.m_pBitmap->GetHBITMAP(Gdiplus::Color::Transparent, &hBitmap);
ImageList_AddMasked(*pList, hBitmap, 0);
}
}
This assume images are all 32x32 pixels. If images are different sizes, they have to be resized before being added to image list.
{
CGdiPlusBitmapResource gdibmp;
if (gdibmp.Load(id, _T("PNG"), AfxGetResourceHandle()))
{
//resize image to 32x32 pixels
Gdiplus::Bitmap newBmp(32, 32, PixelFormat32bppPARGB);
double oldh = (double)gdibmp.m_pBitmap->GetHeight();
double oldw = (double)gdibmp.m_pBitmap->GetWidth();
double neww = 32;
double newh = 32;
double ratio = oldw / oldh;
if (oldw > oldh)
newh = neww / ratio;
else
neww = newh * ratio;
Gdiplus::Graphics graphics(&newBmp);
graphics.SetInterpolationMode(Gdiplus::InterpolationMode::InterpolationModeHighQualityBicubic);
graphics.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias);
graphics.DrawImage(gdibmp.m_pBitmap, 0, 0, (int)neww, (int)newh);
//add `newBmp` to image list
HBITMAP hBitmap;
newBmp.GetHBITMAP(Gdiplus::Color::Transparent, &hBitmap);
ImageList_AddMasked(m_ImageList, hBitmap, 0);
}
}
Using GdiPlus::GetHICON to get the icon handle... With CGdiPlusBitmapResource class, it should be possible to use the following:
HICON hicon;
m_pBitmap.Load(IDB_RIBBON_HOMELARGE, _T("PNG"), AfxGetResourceHandle());
m_pBitmap.m_pBitmap->GetHICON(&hicon);
pList->Add(hicon);
or using GetHBITMAP
Also make sure Visual Styles is enabled for improved appearance of ListView icons.
Test image with transparent background:
The PNG image contains pixels that are partially transparent (alpha < 255). That's a pretty common accident with a program like Photoshop, the most likely cause is overlaying the spyglass image on top of the document image and not merging the layers correctly.
As given, the image can only look good when it is displayed on top of the light-gray or white background. But that didn't happen, the background was black. Now making the anti-aliasing pixels around the spyglass painfully obvious, they turned various shades of dark-gray depending on their alpha value and no longer blend with the white background of the document image. A very typical mishap when you use GDI functions, it does not like alpha.
You can doctor it with GDI+, ensuring that the background color is correct. But that's a fair amount of work and it still leaves you with the trouble of guessing at the original background color correctly.
Just really rather best to go back to whatever painting tool you used and fix the problem there. Quickest fix ought to be re-saving it as a 24bpp BMP image file, ymmv.

Resources