How do I use the scanCrop property of a ZBar reader? - objective-c

I am using the ZBar SDK for iPhone in order to scan a barcode. I want the reader to scan only a specific rectangle instead of the whole view, for doing that it is needed to set the scanCrop property of the reader to the desired rectangle.
I'm having hard time with understanding the rectangle parameter that has to be set.
Can someone please tell me what rect should I give as an argument if on portrait view its coordinates would be: CGRectMake( A, B, C, D )?

From the zbar's ZBarReaderView Class documentation :
CGRect scanCrop
The region of the video image that will be scanned, in normalized image coordinates. Note that the video image is in landscape mode (default {{0, 0}, {1, 1}})
The coordinates for all of the arguments is in a normalized float, which is from 0 - 1. So, in normalized value, theView.width is 1.0, and theView.height is 1.0. Therefore, the default rect is {{0,0},{1,1}}.
So for example, if I have a transparent UIView named scanView as a scanning region for my readerView. Rather than do :
readerView.scanCrop = scanView.frame;
We should do this, normalizing every arguments first :
CGFloat x,y,width,height;
x = scanView.frame.origin.x / readerView.bounds.size.width;
y = scanView.frame.origin.y / readerView.bounds.size.height;
width = scanView.frame.size.width / readerView.bounds.size.width;
height = scanView.frame.size.height / readerView.bounds.size.height;
readerView.scanCrop = CGRectMake(x, y, width, height);
It works for me. Hope that helps.

You can use scan crop area by doing this.
reader.scanCrop = CGRectMake(x,y,width,height);
for eg.
reader.scanCrop = CGRectMake(.25,0.25,0.5,0.45);
I used this and its working for me.

come on!!! this is the right way to adjust the crop area;
I had wasted tons of time on it;
readerView.scanCrop = [self getScanCrop:cropRect readerViewBounds:contentView.bounds];
- (CGRect)getScanCrop:(CGRect)rect readerViewBounds:(CGRect)rvBounds{
CGFloat x,y,width,height;
x = rect.origin.y / rvBounds.size.height;
y = 1 - (rect.origin.x + rect.size.width) / rvBounds.size.width;
width = rect.size.height / rvBounds.size.height;
height = rect.size.width / rvBounds.size.width;
return CGRectMake(x, y, width, height);
}

Related

iOS Core Graphics how to optimize incremental drawing of very large image?

I have an app written with RXSwift which processes 500+ days of HealthKit data to draw a chart for the user.
The chart image is drawn incrementally using the code below. Starting with a black screen, previous image is drawn in the graphics context, then a new segment is drawn over this image with certain offset. The combined image is saved and the process repeats around 70+ times. Each time the image is saved, so the user sees the update. The result is a single chart image which the user can export from the app.
Even with autorelease pool, I see spikes of memory usage up to 1Gb, which prevents me from doing other resource intensive processing.
How can I optimize incremental drawing of very large (1440 × 5000 pixels) image?
When image is displayed or saved at 3x scale, it is actually 4320 × 15360.
Is there a better way than trying to draw over an image?
autoreleasepool {
//activeEnergyCanvas is custom data processing class
let newActiveEnergySegment = activeEnergyCanvas.draw(in: CGRect(x: 0, y: 0, width: 1440, height: days * 10), with: energyPalette)
let size = CGSize(width: 1440, height: height)
UIGraphicsBeginImageContextWithOptions(size, false, 0.0)
//draw existing image
self.activeEnergyImage.draw(in: CGRect(origin: CGPoint(x: 0, y: 0),
size: size))
//calculate where to draw smaller image over larger one
let offsetRect = CGRect(origin: CGPoint(x: 0, y: offset * 10),
size: newActiveEnergySegment.size)
newActiveEnergySegment.draw(in: offsetRect)
//get the combined image
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
//assign combined image to be displayed
if let unwrappedImage = newImage {
self.activeEnergyImage = unwrappedImage
}
}
Turns out my mistake was in passing invalid drawing scale (0.0) when creating graphics context, which defaulted to drawing at the device's native screen scale.
In case of iPhone 8 it was 3.0 The result is needing extreme amounts of memory to draw, zoom and export these images. Even if all debug logging prints that image is 1440 pixels wide, the actual canvas ends up being 1440 * 3.0 = 4320.
Passing 1.0 as the drawing scale makes the image more fuzzy, but reduces memory usage to less than 200mb.
// UIGraphicsBeginImageContext() <- also uses #3x scale, even when all display size printouts show
let drawingScale: CGFloat = 1.0
UIGraphicsBeginImageContextWithOptions(size, true, drawingScale)

SVG image within a Batik JSVGCanvas is scaled down after rotation and setting bounding box

I have a problem with the rotation within a JSVGCanvas.
The user can load SVG images into a document page (JLayeredPane).
Every image displays in his own JSVGCanvas and has his own class.
The user can resize the image by dragging the endpoints and also move the image around.
The rotation works perfectly
(Basic and rotated situation)
Only the subsequent change of the bounding box of the Canvas results in a scaling, which no longer corresponds to the original size
(Finally after setting Boundingbox)
Code fragment in UpdateManager():
....
// calculating new canvas bounding box
AffineTransform at = AffineTransform.getRotateInstance(rotation*Math.PI/180.0,
originalX + originalW/2.0,
originalY + originalH/2.0);
Rectangle2D.Double rect = new Rectangle2D.Double(originalX, originalY, originalW, originalH);
Shape s = at.createTransformedShape(rect);
xx = s.getBounds2D().getX();
yy = s.getBounds2D().getY();
ww = s.getBounds2D().getWidth();
hh = s.getBounds2D().getHeight();
canvas.setRenderingTransform(AffineTransform.getRotateInstance(rotation*Math.PI/180.0,
originalW/2.0, originalH/2.0));
// this.setBounds() will do the stuff and also change the Canvas Bounds
setBounds(xx, yy, ww, hh);
....
I am grateful for any help.
Solved...
I have found the way to solve this problem:
....
// calculating new canvas bounding box
AffineTransform at = AffineTransform.getRotateInstance(rotation*Math.PI/180.0,
originalX + originalW/2.0,
originalY + originalH/2.0);
Rectangle2D.Double rect = new Rectangle2D.Double(originalX, originalY, originalW, originalH);
Shape s = at.createTransformedShape(rect);
xx = s.getBounds2D().getX();
yy = s.getBounds2D().getY();
ww = s.getBounds2D().getWidth();
hh = s.getBounds2D().getHeight();
double rotScale = originalW/ww;
double diffX = (originalW * rotScale - originalW) / 2.0 * -1.0;
double diffY = (originalH * rotScale - originalH) / 2.0 * -1.0;
AffineTransform af = AffineTransform.getScaleInstance(rotScale, rotScale);
af.preConcatenate(AffineTransform.getTranslateInstance(diffX, diffY));
af.preConcatenate(AffineTransform.getRotateInstance(rotation*Math.PI/180.0, originalW/2.0, originalH/2.0));
canvas.setRenderingTransform(af);
// this.setBounds() will do the stuff and also change the Canvas Bounds
setBounds(xx, yy, ww, hh);
....
Maybe this will help others having the same problem.
Picture solved

Calculte new width and height of the video based on the original width, height and ratio

After searching through - I wasn't able to find the answer so I'll give it a shot here.
I need to resize desktop video in order to feet it on mobile screen, let's say original width of the video was 1915 and original height was 1075, I calculated aspect ratio:
aspectRatio = (width/height); aspectRatio = 1.78;
Now my mobile screen resolution is: height = 1609, width = 1080.
How can I properly resize my video in order to keep the same aspect ratio??
Thank you
aspectRatio = (width/height)
You always want aspectRatio to be 1.78, if you want to prevent stretching or cropping.
And, the max new height is 1609 and the max new width is 1080, so:
1.78 = (1080/height)
height = 1080/1.78 = 606.74...
OR
1.78 = (width/1609)
width = 1.78*1609 = 2864.02...
So, you can have 1080x606.74 (which fits on screen), or 2864.02x1609 (which doesn't fit).
So, your answer is 1080x606.74...
Let's original dimensions are Wo, Ho, and target screen dimensions are Wt, Ht.
Rectangle with predetermined aspect will fit vertically if ratio of target and initial heights less than ratio of its widths, and will fit horizontally otherwise:
Coeff = Min(Wt/Wo, Ht/Ho)
W_Result = Wo * Coeff
H_Result = Ho * Coeff
or
if (Wt * Ho < Ht * Wo) then
W_Result = Wt
H_Result = Ho * Wt / Wo
else
W_Result = Wo * Ht / Ho
H_Result = Ht

OpenGL ES 2.0 blending

I set glBlendFunc to
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
and for testing purposes I set the color in my fragment shader like this
gl_FragColor = vec4(1.0,0.0,0.0,0.0);
Shouldn't the object be fully transparent? What could the reason be if it's not?
The first argument of glBlendFunc() is the source factor, the second is the destination factor. In your case:
sfactor = 1.0;
dfactor = 1.0 - src.alpha;
being src.alpha = 0.0, from your gl_FragColor:
sfactor = 1.0;
dfactor = 1.0;
So the color put to the buffer will be:
buffer = sfactor * src + dfactor * dst;
Substituting...
buffer = (1.0,0.0,0.0,0.0) + dst;
So, putting it simple, you are adding 1 to the red channel of the existing buffer.
If you want to make the output fully transparent, the usual function is:
glBlendFunc(GL_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
The one you wrote is usually used for pre-multiplied alpha in the source. But (1, 0, 0, 0) is obviously not a premultiplied alpha value!

Image scale from center of display using matrix

every one.
I'm a android developer.
I want to scale my image from center of displayed part of image with matrix.
So, I scaled my image with matrix. And then moved it with the calculated pointer.
But, the Application not work correctly.
This can't find the correct center, so when it does, it moved right.
Why this is?
I can't find the problem.
The code followed.
matrix.reset();
curScale += 0.02f;
orgImage.getHeight();
w = orgImage.getWidth();
matrix.postScale(curScale, curScale);
rtnBitmap = Bitmap.createBitmap(orgImage, 0, 0, w, h, matrix, true);
curImageView.setImageBitmap(rtnBitmap);
Matrix curZoomOutMatrix = new Matrix();
pointerx =(int ) ((mDisplayWidth/2 - curPosX) * curScale);
curPosX = - pointerx;
pointery =(int ) ((mDisplayWidth/2 - curPosY) * curScale);
curPosY = - pointery;
Log.i("ZoomOut-> posX = ", Integer.toString(curPosX));
Log.i("ZoomOut-> posY = ", Integer.toString(curPosY));
curZoomOutMatrix.postTranslate(curPosX, curPosY);
curImageView.setImageMatrix(curZoomOutMatrix);
curImageView.invalidate();
Did you have any sample code for center zoomIn and zoomOut the imageView with matrix?
Who can explain for that?
Please help me.
Or, It's my fault.
First, I scale the image from original one.
So, The image is (width, height) * scale;
Then I calculate the absolute position of the point that is displayed center. And then, move my ImageView to the calculated position from which the view is. My fault are here.
When i calculate view position, I change the position from now scale.
So, when it scaled, the position is not <original position> * <now scale>. It was <original position * <scale> * <now scale>, the result was strange position.
So i remade add to calculate the center position from original one.
That mode is now following.
public void calculate(float offset) {
float tmpScale = curScale - offset;
float orgWidth = (mDisplayWidth / 2 - curPosX) / tmpScale;
float orgHeight = (mDisplayHeight / 2 - curPosY) / tmpScale;
int tmpPosX = (int)(mDisplayWidth / 2 - orgWidth * curScale);
int tmpPosY = (int)(mDisplayHeight / 2 - orgHeight * curScale);
curPosX = tmpPosX;
curPosY = tmpPosY;
Matrix matrix = new Matrix();
matrix.postTranslate(tmpPosX, tmpPosY);
curImageView.setImageMatrix(matrix);
curImageView.invalidate();
}
Thank you. every one.