Jump to content

MJW

Members
  • Posts

    2,848
  • Joined

  • Last visited

  • Days Won

    70

Everything posted by MJW

  1. Thanks for the congratulations, and thanks to the other entrants. Though there were few, I found them all to be enjoyable. Thanks, of course, to our host, Drew!
  2. 1) According to Forum Rule 6: "Thread titles must be descriptive and specific -- NOT generic." You can change the topic title by editing your original comment, selecting Use Full Editor, and editing the Topic Title. 2) Changing the shirt color is doable; changing the shirt to a different shirt is probably quite difficult.
  3. Plugins can only see the active layer. (I wish they could see, but not modify, other layers, but they can't.)
  4. Not Rebel Wolf Clan? A typo, or a Tarantino-esque "Inglourious Basterds" thing?
  5. I use precise selections a lot less than I used to. Cc4FuzzyHuggles suggests using alpha masks, and that's the sort of approach I often use. Selections are mostly selected or not selected, while alpha mask methods allow more subtle transitions. EDIT 2: Another method I often use is to duplicate the layer and then erase the "selected" area in the upper layer. Any adjustments to the lower layer will only affect that region in the merged image. EDIT: I obviously need to read the other comments more closely, since I originally repeated the suggestion Cc4FuzzyHuggles made about painting on another layer.
  6. One possible method is to use Layer>Rotate/Zoom to untilt the original image, making the subsequent section and mirroring simpler. Then retilt the image when finished.The double tilting would probably result in some blurring. If you first increase the canvas size, you'll avoid clipping the picture edges.
  7. You're right, of course. Don't know what I was thinking. How about following the B&W with Adjustments>Posterize, with the number of levels set to 2. That should work. A more flexible choice is Ed Harvey's Threshold plugin. (A disadvantage is that it's part of a large plugin package. They are, however, very useful effects.)
  8. Perhaps Adjustments>Black and White (Ctrl+Shift+G).
  9. Instead of flattening, you could use Select All, Copy Merged, then Paste into New Image (which can also be accomplished by the easier: Ctrl+Shift+C followed by Ctrl+Alt+V). Then resize (Ctrl+R) and save (Ctrl+S) the new image. Not great, but perhaps better than modifying the original image. Only a filetype plugin could do what you want, and as far as I can see from the plugin list, there currently isn't one that does that. (I'm don't know much about filetype plugins, but from what I know, I think one could probably be written to do what you want.)
  10. So I don't keep you waiting, here is a version that seems to work. I'm still trying to reconcile some differences in this code and Rotate/Zoom in how tilt angles are treated. The Rotate/Zoom angles have to be a little larger to produce the same image. I added an extra control, purely for experimental purposes. It's called Perspective Scale, and amounts to how far away the viewer is from the plane. The larger the value, the less rapidly the lines will converge. I'm not sure the way I handle this is the most sensible, and I don't currency understand how the equivalent feature is handled by Rotate/Zoom. (It's constant in Rotate/Zoom, but I don't know how that constant is determined.) To produce the same distortion as Rotate/Zoom with a 75 degree tilt, I used a 72.3 degree tilt, and a Perspective Scale of 3.43. I don't yet fully understand the computations in Rotate/Zoom. They're kind of confusing, and of course, the disassembly has no comments. As you can see, the changes are pretty minor. Just computing two values in Render, and replacing the perspective code in the transformation. Note I compute W in the perspective code, but don't divide by it till the rotate and zoom are complete. W is unaffected by those transformations, and doesn't affect them. Hidden Content: // Name: Wat Tyler // Author: Red ochre (John Robbins) // Submenu: Test // URL: http://www.getpaint.net/redirect/plugins.html // Title: Wat Tyler Bad Tilt Beta 9/5/16 Red Ochre #region UICode Pair<double, double> Amount1 = Pair.Create( 0.0 , 0.0 ); // Centre byte Amount2 = 1; // Tiling options|reflect|repeat|reflect brick|repeat brick|clamp|none bool Amount3 = true; // [0,1] Limit to integers double Amount4 = 1; // [1,20] Horizontal(X) zoom out double Amount5 = 1; // [1,20] Vertical (Y) zoom out bool Amount6 = true; // [0,1] Link X & Y zoom double Amount7 = 0; // [0,90] Tilt back angle BAD! double Amount8 = 0; // [-180,180] Rotation bool Amount9 = true; // [0,1] Limit rotation (15 degree steps) bool Amount10 = false; // [0,1] Faster (lower quality) double Amount11 = 3.0; //[1,20] Perspective Scale (for demonstation purposes) #endregion double PI = Math.PI; double PI2 = Math.PI/2; // Methods here private ColorBgra move (Surface src,float X,float Y,float xoffset,float yoffset,float Xzoom,float Yzoom,float cosZ,float sinZ, double Tangle) { Rectangle sel = this.EnvironmentParameters.GetSelection(src.Bounds).GetBoundsInt(); int sL = sel.Left; int sR = sel.Right; int sT = sel.Top; int sB = sel.Bottom; int H = sel.Height; int W = sel.Width; float hW = (float)(W)/2; float hH = (float)(H)/2; ColorBgra Np; //let C be the centre of zoom and rotation at a moveable but static position. //1. subtract selection top or left //2. work out distance to (moveable but static) crosshairs //3. distort new xdist & ydist for rotation. //4. distort for zoom out //5. currently distort for tilt back VERY WRONG!!! // Ideally this would be calculated in Render to change the number of samples made. //6. feed new x & y through tesselation methods. //7. add back selection top and left and access pixel values to feed back to SSpix method, // where average taken and fed back to Render float Cx = xoffset + hW; float Cy = yoffset + hH; float xdist = X - Cx;//selection.Left not in X (only in x) float ydist = Y - Cy; //try tilt here to get maths correct-------------------- //DOES NOT WORK // I have tried every possible calculation I can think of here: // Tanh, powers etc etc etc. // I always end up with curved perspective lines? // It really hurts me to give up but I just don't have the understanding of mathematics to do this correctly // //float xwarpT = xdist; //float ywarpT = ydist; //float Hrat = (H -Y)/H; //float iHrat = 1 - Hrat; //xwarpT = (float)((xdist + iHrat) + (Hrat * Math.Tan(Tangle) * xdist));//curved //ywarpT = (float)((ydist + iHrat) + (Hrat * Math.Tan(Tangle) * ydist * 8));//all rubbish float ywarpT = yTiltScale * ydist; float w = wTiltScale * ydist + 1.0f; //----------------------------Ends Tilt ------------------- float xwarpR = (cosZ * xdist) - (sinZ * ywarpT);//Rotation float ywarpR = (cosZ * ywarpT) + (sinZ * xdist); float xwarpZ = xwarpR * Xzoom;//Zoom out float ywarpZ = ywarpR * Yzoom; if (w <= 0.0f) { Np = ColorBgra.Transparent; } else { float recipW = 1.0f / w; xwarpZ *= recipW; ywarpZ *= recipW; float nxP = xwarpZ + hW; float nyP = ywarpZ + hH; bool Oob = false;//out of bounds for case 5 only float repx = (int)Math.Abs(nxP/W);// NOW FLOAT! (really int but saves loads of boxing/casting) float repy = (int)Math.Abs(nyP/H); //Syntax,value of this = condition ? value if true:value if false //REMEMBER selection irrelevant here!!! use W, H & zero only. switch(Amount2) { case 0://reflect - default if(nxP < 0 ){nxP = - nxP;} if(nxP >= W ){nxP = repx%2 >= 1 ? W - nxP%W: nxP%W;} if(nyP < 0 ){nyP = - nyP;} if(nyP >= H ){nyP = repy%2 >= 1 ? H - nyP%H: nyP%H;} break; case 1://repeat if(nxP < 0){nxP = W - Math.Abs(nxP%W);} if(nxP >= W){nxP = nxP%W;} if(nyP < 0){nyP = H - Math.Abs(nyP%H);} if(nyP >= H){nyP = nyP%H;} break; case 2://brick reflect if(nyP >= 0){repy += 1;}//must be first if(repy%2 == 0 ){nxP = hW + nxP;} repy = (int)Math.Abs(nyP/H);//must be re-calculated as changed values repx = (int)Math.Abs(nxP/W); if(nxP < 0){nxP = - nxP;} if(nxP >= W){nxP = repx%2 >= 1 ? W - nxP%W: nxP%W;} if(nyP < 0){nyP = - nyP;} if(nyP >= H){nyP = repy%2 >= 1 ? H - nyP%H: nyP%H ;} break; case 3://brick repeat nyP = nyP + 0.0000001f;//bodge!!!! - no idea where the real bug is? if(nyP > 0){repy += 1;} if(repy%2 == 0){nxP = hW + nxP;} if(nxP < 0){nxP = W - Math.Abs(nxP%W);} nxP = nxP%W; if(nyP < 0){nyP = H - Math.Abs(nyP%H);} nyP = nyP%H; break; case 4://clamp if(nxP < sL){nxP = sL;} if(nxP > sR){nxP = sR;} if(nyP < sT){nyP = sT;} if(nyP > sB){nyP = sB;} break; case 5://none if(nxP < sL || nxP > sR || nyP < sT || nyP > sB){Oob = true;} break; } nxP = nxP + sL;//add selection top and left back in nyP = nyP + sT; ColorBgra klear = ColorBgra.Transparent; Np = src.GetBilinearSampleClamped(nxP,nyP); if(Oob){Np = klear;} } return Np; } private ColorBgra SSpix(Surface src,int x, int y,float Xstep,float Ystep, int xsamples, int ysamples,float xoffset,float yoffset,float Xzoom,float Yzoom,float cosZ,float sinZ,double Tangle) { //Sub-pixel Sampling method ColorBgra SStemp = ColorBgra.Aquamarine; int SSno = xsamples * ysamples; int B = 0;int G = 0;int R = 0;int A = 0; float tempB = 0;float tempG = 0;float tempR = 0;float tempA = 0; float X = 0;float Y = 0; double Trat = 0; Rectangle sel = EnvironmentParameters.GetSelection(src.Bounds).GetBoundsInt(); double H = sel.Height; for (int Ys = 0; Ys < ysamples;Ys++) { Y = (y - sel.Top) + (Ys * Ystep); for (int Xs = 0; Xs < xsamples;Xs++) { X = (x - sel.Left) + (Xs * Xstep);//note: now float SStemp = move(src, X, Y, xoffset, yoffset, Xzoom, Yzoom, cosZ, sinZ, Tangle); tempB += SStemp.B; tempG += SStemp.G; tempR += SStemp.R; tempA += SStemp.A;// sum values } } B = (int)(tempB/SSno);//end of SPS loop... divide by number of pixels sampled to find average G = (int)(tempG/SSno); R = (int)(tempR/SSno); A = (int)(tempA/SSno); return ColorBgra.FromBgra(Int32Util.ClampToByte(, Int32Util.ClampToByte(G), Int32Util.ClampToByte(R), Int32Util.ClampToByte(A)); } // There's nothing wrong with using "global" variables (which are actually class variables) // to communicate with subroutines, provided that the values never change during the // rendering process. The values are state, not arguments. It seems to me to be so much // neater than passing a huge number of unchanging arguments. float yTiltScale; float wTiltScale; void Render(Surface dst, Surface src, Rectangle rect) { Rectangle sel = EnvironmentParameters.GetSelection(src.Bounds).GetBoundsInt(); float W = (float) sel.Width; float hW = (float)(sel.Width/2); float hH = (float)(sel.Height/2); float H = (float)sel.Height; int B = 0; int G = 0; int R = 0; int A = 0; int tempB = 0; int tempG = 0; int tempR = 0; int tempA = 0; ColorBgra cp = ColorBgra.Aquamarine; //just to declare a value float xoffset = (float)(Amount1.First * hW); float yoffset = (float)(Amount1.Second * hH); float Xzoom = (float)Amount4; float Yzoom = (float)Amount5;if(Amount6){Yzoom = (float)Amount4;} if(Amount3){Xzoom = (int)(Xzoom);Yzoom = (int)(Yzoom);} int xsamples = (int)Xzoom; int ysamples = (int)Yzoom; float Xstep = (float)(1.0/xsamples); float Ystep = (float)(1.0/ysamples); double Zrot = PI * Amount8/180;//all in radians now if(Amount9){int uaf = (int)(Amount8/15);Zrot = PI * (uaf * 15)/180;}//confine to multiples of 7.5 degrees float cosZ = (float)Math.Cos(-Zrot); float sinZ = (float)Math.Sin(-Zrot);//just prefer things rotating as the slider does double Tangle = PI * Amount7/180;//-ve halfPI to +ve PI double tanT = Math.Tan(Tangle), cosT = Math.Cos(Tangle); yTiltScale = (float)(1.0 / cosT); wTiltScale = (float)(tanT) / ((float)Amount11 * hH); for (int y = rect.Top; y < rect.Bottom; y++) { for (int x = rect.Left; x < rect.Right; x++) { double Trat = (H - (y - sel.Top))/H; if(Amount10){xsamples = ysamples = 1;} cp = SSpix(src,x,y,Xstep,Ystep,xsamples,ysamples,xoffset,yoffset,Xzoom,Yzoom,cosZ,sinZ,Tangle);//call Sub-pixel sampling method here dst[x,y] = cp; } } } EDIT: I'm convinced I'm not doing the perspective transformation correctly. The foreshortening is wrong, so the image stretches in Y as the tilt increases. I have an idea why, but I'll need to do a little math. I tried to derive it using 3x3 matrices instead of the usual 4x4, and I think it led me astray. EDIT 2: What a silly mistake! The posted code seems just fine. I was experimenting with something in my version, and managed to use the wrong version of the Y coordinate at one step in the process. Arghh!
  11. The sub-pixel sampling should be no problem. Just as it currently does, it will take a destination pixel location and transform it into a source pixel location, which can then accessed with the bilinear sample routines. The destination locations can be for sub-pixels as well as pixels.
  12. I've had a chance to look at the code, and I'll try to fix the perspective transformation soon (sometime today, I hope), then post the modified version or put it somewhere you can retrieve it.
  13. 3) Unselect a layer auto selects the next layer Amen to that. I've griped about that behavior, as have others. It's supposed to be a feature to prevent making changes that can't be seen, but I've never understood why making changes to the wrong layer is a better alternative. I wish there were either a setting to disable that behavior, or that disabling and re-enabling a layer with no intervening steps would leave the layer enabled. I often toggle a layer off and on to make sure it's the layer I think it is.
  14. I believe the only way to get the perspective correct is to use homogeneous coordinates. That may sound complicated, but it just involves addition, multiplication, and division. This explanation probably won't be enough to write code from, but it may make it clearer how it works. You start of with the image coordinates, (x, y). There's an assumed "w" coordinate of 1, so it can be considered to be (x, y, 1). (I call it "w", but others might call it "z". It represents the distance from the viewer.) The coordinates are transformed to other coordinates using a transformation: x' = Mxx * x + Mxy * y + Mxw y' = Myx * x + Myy * y + Myw w' = Mwx * x + Mwy * y + Mww The nine values, Mxx, Mxy, Mxw, etc., depend on how the image is transformed; that is, how it's rotated, translated, and scaled. This is usually thought of as a matrix multiplication, written: / x' \ / Mxx Mxy Mxw \ / x \ | y' | = | Myx Myy Myw | | y | \ w' / \ Mwx Mwy Mww / \ 1 / Now this has three components, x', y', w', yet you can only display two. The two coordinates are produced by dividing x' and y' by w': x" = x'/w' y" = y'/w' The division is called the "perspective division," and it's what causes the size of objects to decrease as they get farther away. Here's the tricky part. In PDN plugins, you need to solve the opposite problem. You start with (x", y"), which are the coordinates of the destination pixel, and you need to find the (x, y) coordinates in the source image that will transform to them. Fortunately, it's not too difficult, because the whole process is reversible. The matrix can be "inverted" to produce a new matrix such that: / x* \ / Mxx' Mxy' Mxw' \ / x" \ | y* | = | Myx' Myy' Myw' | | y" | \ w* / \ Mwx' Mwy' Mww' / \ 1 / or, x* = Mxx' * x" + Mxy' * y" + Mxw" y* = Myx' * x" + Myy' * y" + Myw" w* = Mwx' * x" + Mwy' * y" + Mww" Then the points that are used in src.GetBilinearSampleClamped(x, y) are: x = x*/w* y = y*/w* (if w* is less than or equal to 0, the point is behind the viewer, so it's invisible.) So, once the values for Mxx', Mxy', Mxw', Myx', Myy', Myw', Mwx', Mwy', Mww' are known, it's just a matter of some multiplications, additions, and divisions. I don't understand what you're doing in the plugin well enough yet to tell you how to find the values. I downloaded the code, so I can probably figure it out, but it would help if you'd explain it a little. (In case it isn't clear, the primes (' and ") and star (*) are just used to distinguish between different versions of the coordinates.) (Also, one small technical point: because the x and y values are divided by w, all the matrix entries can be scaled by the same amount without affecting the result. Therefore, the transposed co-factor matrix can be used instead of the inverted matrix, which simplifies the computation a bit. Also, the total transformation is usually a combination of easily invertible operations, such as "rotate about the x axis," followed by "translate in the x and y direction," etc. The total inverse is just the individual inverses in reverse order. (Don't worry if that's not clear. I'm just trying to show that the computations involved are usually not particularly difficult.))
  15. If you mean that grainy effect (which seems to be the only distinctive color effect), you might try something like: Set the Primary Color to black, and the Secondary Color to red. Run Effects>Render>Clouds. Set the Scale to 5, the Roughness to the default 50, and the Blend Mode to Normal. Re-run Clouds, this time with the Scale set to 6, the Roughness to the default 50, and the Blend Mode to Glow. There are lots of possible variations that will produce somewhat different results. (If you mean something other than the grainy effect, I think you'll need to be more specific, and perhaps provide an example of the image you want to start from.) EDIT: The only other effect I see in the image is the lightening of some of the red areas. That can be achieved by adding another layer on top, making it white in the lightened regions and transparent elsewhere, then setting the Opacity of the layer to around 50.
  16. One idea that might be worth a try: Run Effects>Noise>Median, setting the Radius to 2, and leaving the Percentile at 50. Repeat until the lines are wide enough. (I can't quite say off hand why it widens the lines, but it does.)
  17. The easiest way I can think of is: Convert the image to black and white with Adjustments>Black and White Using the Layer menu add a new layer. Move the new layer, which will be on top, to the bottom. Select the new layer. Fill the new layer with blue. Deselect (to make the final result easier to see). Change the Blend Mode of the image layer (top layer) to Screen. EDIT: Easier: Run Adjustments>Hue /Saturation. Set Saturation to 200, Hue to around -164. (The final result is a bit different than the first method.)
  18. I think only administrators can move threads. You can, however, fix the spelling of "areas" in the title. Just edit your original comment, then select the Use Full Editor option. You will be able to edit the Topic Title.
  19. Effects>Color>Make Transparent may be useful. It replaces a selected color (which includes black or white) with transparency, so that the image will look the same if placed above a background layer of the selected color. I believe when used with black or white as the selected color it gives the same result as BoltBait's Switch Gray to Alpha, so either would work well. Switch Gray to Alpha is easier to use for making black and white transparent; Make Transparent works with color, also.
  20. There's a useful website called TinEye that will search the web for an image. I tried it with an image I'd added text to, and it found the original image. I imagine it's rather hit and miss in doing that, depending on how much the image has been modified, but you might give it a try.
  21. Those are some very useful features! I assume (or at least hope) that the first and second Color Wheel control will still default to the Primary and Secondary color if left unspecified.
  22. In fact, if you have a selection, Object Align will center the object relative to the selection boundary. The object to be centered must be inside the selection.
  23. As AgentGoodspeed points out, Object Align does something similar. It's a very useful plugin, which most every PDN user should install. I'll add that the original proposed method isn't possible, since a plugin can't move the text outside the selection that's in place when the plugin is run. Plugins can't change the selection or write outside the selection.
  24. Appearances can be deceiving, but PDN is an image editor, so appearance matters a great deal. (In contrast to vehicles, where appearance is a secondary consideration.) I wish there were more options for how Magic Wand selections are made, but there's only one, so it ought to be the most practical for the widest variety of situations. Generally -- I'd say the vast majority of times -- the user doesn't care whether a completely transparent pixel's color fields are white, black, or purple; no matter what the RGB values, if the alphas are 0, they're all transparent, and they all affect the appearance of the image in the same way.
×
×
  • Create New...