Bitmap Image: cropping with portrait orientation - win-universal-app

Adding camera functionality to my app is killing me! Started with the basic UWP camera sample, but I have to add zooming capability which added a ScrollViewer around the preview control and complicated my life. Found the cropping code in a different sample. Everything works in landscape, but when you rotate the tablet to portrait the cropped image (even without any actual cropping) is rotated 90.
The cropping logic takes originX/Y, ScrollViewer.ViewportWidth/Height & ScrollViewer.ExtentWidth/Height. I don't understand how these values change with the rotation! In Landscape I use topLeft for the X/Y. What would I do for Portrait? I'm setting the width to 400 and in both views it's STILL 400 so I don't believe width/height should be flipped.
Here's the cropping code. Can anyone comment on what should be different for the 2 (actually 4) orientations?
async public static Task<WriteableBitmap> GetCroppedBitmapAsync(StorageFile originalImageFile,
Point startPoint, Size cropSize, Size previewSize)
{
using (IRandomAccessStream stream = await originalImageFile.OpenReadAsync())
{
// Create a decoder from the stream. With the decoder, we can get the properties of the image.
BitmapDecoder decoder = await BitmapDecoder.CreateAsync(stream);
// Adjust the start x/y to the stream size
uint scaledStartPointX = (uint)Math.Round((decoder.PixelWidth * (startPoint.X / previewSize.Width)));
uint scaledStartPointY = (uint)Math.Round((decoder.PixelHeight * (startPoint.Y / previewSize.Height)));
// Now get the scaled size of the viewport (ie the cropped area)
uint selectedAreaWidth = (uint)Math.Round(decoder.PixelWidth * (cropSize.Width / previewSize.Width));
uint selectedAreaHeight = (uint)Math.Round(decoder.PixelHeight * (cropSize.Height / previewSize.Height));
// Get the cropped pixels.
byte[] pixels = await GetPixelData(decoder, scaledStartPointX, scaledStartPointY, selectedAreaWidth, selectedAreaHeight,
decoder.PixelWidth, decoder.PixelHeight);
// Stream the bytes into a WriteableBitmap
WriteableBitmap cropBmp = new WriteableBitmap((int)selectedAreaWidth, (int)selectedAreaHeight);
Stream pixStream = cropBmp.PixelBuffer.AsStream();
pixStream.Write(pixels, 0, (int)(selectedAreaWidth * selectedAreaHeight * 4));
return cropBmp;
}
}

Related

Calculating the correct width to resize image to display in a CListCtrl

At the moment I am having to fudge my code like this:
CRect rcList;
m_ListThumbnail.GetClientRect(rcList);
rcList.DeflateRect(25, 25);
// Use monitor 1 to work out the thumbnail sizes
CRect rcMonitor = m_monitors.rcMonitors.at(0);
m_iThumbnailWidth = rcList.Width();
double dHt = ((double)rcMonitor.Height() / (double)rcMonitor.Width()) * (double)m_iThumbnailWidth;
m_iThumbnailHeight = (int)dHt;
I fudge it by deflating the rectangle by 25. m_ListThumbnail is a CListCtrl and I am trying to render my thumbnails so that I do not need a horizontal scroll bar.
When I render the thumbnails of the monitors, I attempt to massage these thumbnail values (incomplete):
nWidth = m_iThumbnailWidth;
double dHt = ((double)rcCapture.Height() / (double)rcCapture.Width()) * (double)m_iThumbnailWidth;
nHeight = (int)dHt;
if (nHeight > m_iThumbnailHeight)
{
AfxMessageBox(L"Need to investigate!");
}
Where rcCapture is the size of the monitor.
If I remove the DeflateRect line, my window displays like this:
As you can see, it is note as I expected. There is a horizontal scroll bar and I have to resize quite a bit to see the thumbnail:
All I want to compute is a set of thumbnail dimensions so that the scaled down monitor image is going to fit in the CListCtrl. I don't really want the user to have to resize the window.
Update
With my adjusted code which now uses the primary monitor aspect ratio to work out the thumbnail sizes (as added above) renders the app with better whitespace:
That was the reason of the extra space at the bottom because the monitors were 16:9 and I was squishing into 4:3. So that is fixed.
But as you can see, using the CListCtrl client width is not sufficient.
Update
This is the rendering code:
// Set the mode first!
SetStretchBltMode(dcImage, COLORONCOLOR);
int iTop = (m_iThumbnailHeight - nHeight) / 2;
// Copy (and resize)
bRet = ::StretchBlt(dcImage, 0, iTop,
nWidth,
nHeight,
dcScreen.m_hDC,
rcCapture.left,
rcCapture.top,
rcCapture.Width(),
rcCapture.Height(), SRCCOPY | CAPTUREBLT);
The control renders the icon with a margin. When I used GetItemPosition function it indicated that the x value was 21. This is why my DeflateRect(25, 25) worked. But I don;t know how the CListCtrl computed that margin value.
Eventually I found out how to do this without deflating, by using the SetIconSpacing function. Like this:
m_ListThumbnail.SetIconSpacing(
CSize(m_iThumbnailWidth, ::GetSystemMetrics(SM_CXHSCROLL)));
Once the above has been done the window looks like this:
Things might be a little different when there are 3 or 4 monitor thumbnails, thus causing a vertical scroll bar. But I only have two monitors to test with.

pdfbox showText width and height setting

I am creating web based app where you annotate a pdf at browser(using pdf.js and fabricjs) and save the annotations at server side (java servlet REST endpoint) using Apache pdfbox (2.0.x). I can overlay images and text using PDPageContentStream's drawImage and showText methods. Also the user may scale the annotations at browser by selecting and dragging it at corners. This is properly scaled for drawImage by adjusting the width parameter based on the scaleX factor set by fabricjs. But for showText I cannot find any options to scale the text. I can adjust the font size, but that won't translate correctly against the corner.
Any thoughts on how to scale (or change height and width) and put a text on pdf using showText method of PDPageContentStream
Thanks in advance
Prem
PDPageContentStream contentStream = new PDPageContentStream(doc, page, AppendMode.APPEND, true, true);
scaleX = signObj.get("scaleX").getAsFloat();
scaleY = signObj.get("scaleY").getAsFloat();
annoType = signObjWrapper.get("annoType").getAsInt();
float x_adjusted = (signObj.get("left").getAsFloat()) + page.getCropBox().getLowerLeftX();
float y_adjusted = -(signObj.get("top").getAsFloat()) + page.getCropBox().getUpperRightY();
if (annoType == SIGN) // this annotation is a sign object
{
contentStream.drawImage(pdImage, x_adjusted,
y_adjusted - (signObj.get("height").getAsFloat() * scaleY),
signObj.get("width").getAsFloat() * scaleX, signObj.get("height").getAsFloat() * scaleY);
contentStream.close();
} else if (annoType == TEXT) {
//Begin the Content stream
contentStream.beginText();
//Setting the font to the Content stream
contentStream.setFont(PDType1Font.COURIER,signObj.get("fontSize").getAsInt());
//Setting the position for the line
contentStream.newLineAtOffset(x_adjusted, y_adjusted - (signObj.get("height").getAsFloat() * scaleY));
//Adding text in the form of string
contentStream.showText(signObj.get("text").getAsString());
//Ending the content stream
contentStream.endText();
//Closing the content stream
contentStream.close();
}

Azure webjob image resize issue

I am using azure web job to save thumb of an image and this is code for doing this
ImageProcessor.Imaging.Formats.FormatBase f;
f = new ImageProcessor.Imaging.Formats.JpegFormat();
Size size = new Size(200, 200);
using (WebClient client = new WebClient())
{
MemoryStream stream = new MemoryStream(client.DownloadData(input));
MemoryStream stream2 = new MemoryStream();
int quality = 110;
do
{
quality = quality - 10;
using (ImageFactory factory = new ImageFactory(false))
{
factory.Load(stream)
.Format(f)
.Resize(size)
//.BackgroundColor(Color.White)
.Quality(quality)
.Save(stream2);
}
} while (stream2.Length > stream.Length || stream2.Length ==100000);
When i add message to queue with this image for example,
job should give me thumb image 200 * 200 but there is trailing black area in top and bottom of resulted image like this which shouldn't be done
Why this is done ???
You're trying to fit a rectangle into a square.
From http://imageprocessor.org/imageprocessor/imagefactory/resize/:
Resize
Resizes the current image to the given dimensions. If EXIF metadata is to be preserved the information contained within will also be updated to match.
public ImageFactory Resize(Size size)
Parameters
size:
The System.Drawing.Size containing the width and height to set the image to.
Passing a 0 for either dimension will omit that dimension.
So, pass in 0 as height to maintain aspect ratio,
Size size = new Size(200, 0);
or use one of the other resize modes: Crop/Min/Max/Stretch

How to measure ImageView before creating bitmap into it?

My ImageView is matching screen size on x-axis and is using remaining space on y-axis in my layout. I want to create bitmap into this ImageView with exactly the same size as the ImageView is. How to make it please? Can it be done by some automatic setting, should I call some measure function?
I tried SetAdjustViewBounds() but it didn't work for me.
Creating Bitmap big enough (I don't like much such a memory wasting) and setting SetScaleType(ImageView.ScaleType.Matrix) works, but still when I'm making drawing operations on canvas, I don't know real size of area I should paint into, both canvas and bitmap height are equal to yScreen while imgWeekView height is pretending to be 0, even though it paints whole desired area with gray color.
imgWeekView = new ImageView(context);
//imgWeekView.SetAdjustViewBounds(true);
imgWeekView.SetScaleType(ImageView.ScaleType.Matrix);
layoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MatchParent, LinearLayout.LayoutParams.WrapContent,1f);
layoutParams.Height = 0;
imgWeekView.LayoutParameters = layoutParams;
Bitmap bitmap = Bitmap.CreateBitmap((int)xScreen, (int)yScreen, Bitmap.Config.Argb8888);
cnvWeekView = new Canvas(bitmap);
imgWeekView.SetImageBitmap(bitmap);
linearLayout.AddView(imgWeekView); //whole activity layout
//Test
cnvWeekView.DrawColor(new Color(128, 128, 128));
Paint paint = new Paint(PaintFlags.AntiAlias);
paint.Color = new Color(255, 255,0);
cnvWeekView.DrawCircle(50, 50, 40, paint);
Finally I found a way how to measure my ImageView and here I will post my answer.
I believed that there should be much easier solution, but maybe there isn't. From this question I took most of the important data:
How to get the width and height of an android.widget.ImageView?
Things look however a little different in my android application and I'm not experienced enough to tell why. I had to change things a little. I had to learn a bit about interfaces and this question helped too.
Implementing the View.IOnTouchListener interface
Here is how I combined things. First I created class that will do the measure.
public class MyPredrawListener : Java.Lang.Object, ViewTreeObserver.IOnPreDrawListener
{
ImageView imageView;
public MyPredrawListener(ImageView img)
{
imageView = img;
}
public bool OnPreDraw()
{
imageView.ViewTreeObserver.RemoveOnPreDrawListener(this);
int finalHeight = imageView.MeasuredHeight;
int finalWidth = imageView.MeasuredWidth;
Bitmap bitmap = Bitmap.CreateBitmap(finalWidth, finalHeight, Bitmap.Config.Argb8888);
imageView.SetImageBitmap(bitmap);
//Test to see result
Canvas cnv = new Canvas(bitmap);
Paint paint = new Paint();
paint.Color = new Color(255, 255, 0);
cnv.DrawColor(new Color(128, 128, 128));
cnv.DrawCircle(finalWidth-50, finalHeight-50, 50, paint);
return true;
}
}
And in code where I create my imageView I set the listener like this.
imgWeekView = new ImageView(context);
MyPredrawListener listener=new MyPredrawListener(imgWeekView);
imgWeekView.ViewTreeObserver.AddOnPreDrawListener(listener);
In OnPreDraw function I put test code to see the result graphically, clearing bitmap to gray color and painting yellow circle to bottom right of a view.

fix a splash screen image to display in j2me

In my j2me App I have tried canvas which works great on Nokia phone but doesn't run on samsung. For that I have to switch to some FORM which in both cases works but only issue is of size, if I create smaller image to fit for both phone screens, one (samsung) shows that ok but other (nokia) leaves a lot more space and vice versa.
I need to have code that could stretch my image and just fix if to the screen size which I basically get by form.getHeight() and form.getWidth() property. I wonder if there is property of Image.createImage(width, height) then why doesn't it stretch it to the value I provide?
my code for that is below
try {
System.out.println("Height: " + displayForm.getHeight());
System.out.println("Width: " + displayForm.getWidth());
Image img1 = Image.createImage("/bur/splashScreen1.PNG");
img1.createImage(displayForm.getHeight(), displayForm.getWidth());
displayForm.append(new ImageItem(null, img1, Item.LAYOUT_CENTER, null));
} catch (Exception ex) {
}
Image
A single image will not fit all screens. But more will do.
The smaller logo image should be less than 96x54, as this is the smallest screen resolution. This image can be used up to the resolution of 128x128 without problems. With bigger resolutions it will look tiny, though.
The bigger logo image should be a bit bigger than 128x128 and can be used up to 240x320.
The code bellow gives as example of how to implement this.
import javax.microedition.lcdui.Image;
import javax.microedition.lcdui.Graphics;
class Splash extends javax.microedition.lcdui.Canvas {
Image logo;
Splash () {
if (getWidth() <= 128) {
// sl stands for Small Logo and does not need to have a file extension
// this will use less space on the jar file
logo = Image.createImage("/sl");
} else {
// bl stands for Big Logo
logo = Image.createImage("/bl");
}
}
protected void paint (Graphics g) {
// With these anchors your logo image will be drawn on the center of the screen.
g.drawImage(logo, getWidth()/2, getHeight()/2, Graphics.HCENTER | Graphics.VCENTER);
}
}
As seen in http://smallandadaptive.blogspot.com.br/2008/10/showing-splash.html
wonder if there is property of Image.createImage(width, height) then why doesn't it stretch it to the value I provide?
Parameters in this method have nothing to do with stretching, see API javadocs:
public static Image createImage(int width, int height)
Creates a new, mutable image for off-screen drawing.
Every pixel within the newly created image is white.
The width and height of the image must both be greater than zero.
Parameters:
width - the width of the new image, in pixels
height - the height of the new image, in pixels
Image class (API javadocs) has two more createImage methods that use parameters called "width" and "height" - one with six, another with four arguments but none of these has anything to do with stretching.
In createImage with six arguments, width and height specify size of the region to be copied (without stretching) from source image.
In method with four arguments, width and height specify how to interpret source ARGB array, without these it would be impossible to find out if, say, array of 12 values represents 3x4 image or 4x3. Again, this has nothing to do with stretching.

Resources