I succesfully installed MuPDF for one of my Android Apps. But the problems is, while rendering I cannot fit the PDF to the screen. Can anybody please suggest me how to achieve this. Thanks!
Edit the measureView method in ReaderView.java to become.
private void measureView(View v) {
// See what size the view wants to be
v.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
// Work out a scale that will fit it to this view
float scale;
if (getWidth()>getHeight())
{
scale = (float)getWidth()/(float)v.getMeasuredWidth();
MIN_SCALE = (float)v.getMeasuredWidth()/(float)getWidth();
MAX_SCALE = MIN_SCALE*5.0f;
}
else
scale = Math.min((float)getWidth()/(float)v.getMeasuredWidth(),
(float)getHeight()/(float)v.getMeasuredHeight());
// Use the fitting values scaled by our current scale factor
v.measure(View.MeasureSpec.EXACTLY | (int)(v.getMeasuredWidth()*scale*mScale),
View.MeasureSpec.EXACTLY | (int)(v.getMeasuredHeight()*scale*mScale));
}
I was getting errors with regard to the MAX and MIN scale final variables, however I made a slight modification to #hassan83's solution. My solution is tested in MuPDF version 1.9a
private void measureView(View v) {
// See what size the view wants to be
v.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
// Work out a scale that will fit it to this view
float scale;
//landscape orientation
if (getWidth() > getHeight())
{
scale = (float)getWidth()/(float)v.getMeasuredWidth() * (1.0f ); //make sure that we fill the page by multiplying with a scale factor of one
}
else
scale = Math.min((float)getWidth()/(float)v.getMeasuredWidth(),
(float)getHeight()/(float)v.getMeasuredHeight());
// Use the fitting values scaled by our current scale factor
v.measure(View.MeasureSpec.EXACTLY | (int)(v.getMeasuredWidth()*scale*mScale),
View.MeasureSpec.EXACTLY | (int)(v.getMeasuredHeight()*scale*mScale));
}
with this the page is resized boot too larger from the view. here is the "measureview" method in my code:
private void measureView(View v) {
// See what size the view wants to be
v.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
if (!mReflow) {
// Work out a scale that will fit it to this view
float scale = Math.min((float) getWidth() / (float) v.getMeasuredWidth(),
(float) getHeight() / (float) v.getMeasuredHeight());
// Use the fitting values scaled by our current scale factor
v.measure(MeasureSpec.AT_MOST | (int) (v.getMeasuredWidth() * (scale + 0.8f) * mScale),
MeasureSpec.AT_MOST | (int) (v.getMeasuredHeight() * (scale+0.8f) * mScale));
} else {
v.measure(View.MeasureSpec.EXACTLY | (int) (v.getMeasuredWidth()),
View.MeasureSpec.EXACTLY | (int) (v.getMeasuredHeight()));
}
}
this is what I need, boot the page need to be fetched in exactly in the view, boot with the text readable.
In addition to answer https://stackoverflow.com/a/21168243/2982225,
you can re-render the view by adding the following code at the end:
requestLayout();
post(this);
again.
So the complete code is as follows (attribution for code before last comment: the accepted answer of this question ):
private void measureView(View v) {
// See what size the view wants to be
v.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
// Work out a scale that will fit it to this view
float scale;
if (getWidth()>getHeight())
{
scale = (float)getWidth()/(float)v.getMeasuredWidth();
MIN_SCALE = (float)v.getMeasuredWidth()/(float)getWidth();
MAX_SCALE = MIN_SCALE*5.0f;
}
else
scale = Math.min((float)getWidth()/(float)v.getMeasuredWidth(),
(float)getHeight()/(float)v.getMeasuredHeight());
// Use the fitting values scaled by our current scale factor
v.measure(View.MeasureSpec.EXACTLY | (int)(v.getMeasuredWidth()*scale*mScale),
View.MeasureSpec.EXACTLY | (int)(v.getMeasuredHeight()*scale*mScale));
// last comment
// to force the initial rendering to the new scale
requestLayout();
post(this);
}
Hope this helps.
Related
I have a custom ImageView that re positions a an image on a web page. The image that is seen on the phone screen should represent the image on the web page.
I am using Matrix.mapPoints(float[] dst, float[] src) to try and get the how much the image is off-set when scaled to correctly frame the image. I am also taking into account the how much the image is scaled, and the size if the image view on the phone compared to the image tag width on the web page.
UpdateImage() in Image view class
public void updateImage() {
final float phoneDisplayScale = (float) getWidth() / (float) getDrawable().getIntrinsicWidth();
float[] m = new float[9];
matrix.getValues(m);
float scale = m[Matrix.MSCALE_X];
float[] arr = {0, 0};
matrix.mapPoints(arr, arr);
//holder.rect = {image_x, image_y, imageWidth, imageHeight}
if (holder != null) {
holder.getRect()[0] = arr[0] / phoneDisplayScale;
holder.getRect()[1] = arr[1] / phoneDisplayScale;
holder.getRect()[2] = scale * (getImageWidth() / phoneDisplayScale);
holder.getRect()[3] = scale * (getImageHeight() / phoneDisplayScale);
Log.i(TAG, "doInBackground: " + Arrays.toString(holder.getRect()));
Log.i(TAG, "doInBackground: " + Arrays.toString(holder.getRect()));
Log.i(TAG, "doInBackground: " + Arrays.toString(holder.getRect()));
}
//
//
// Socket io code
//
//
}
this works when the image is scaled and aligned to so that the top left of the image is in the top left of the ImageView, but you can never zoom in on the bottom right of the image. I also noticed that if I zoom in to the max that the map points method returns the width and height (minus values) of the image.
Ok my logic was a bit off I have changed the position calculation to the following and it now works.
holder.getRect()[0] = (arr[0] / scale) * phoneDisplayScale;
holder.getRect()[1] = (arr[1] / scale) * phoneDisplayScale;
I'm looking for to some way for make a scroll, or scan of a panoramic image in Android. With this I mean show a part of my image adjusting the height of the image (or width in vertical) and automatically moving slowly the view scrolling all the image. For example:
this image its so big to try to see it in a 16:9 device(with a bit of detail i mean), so i want to do something like:
Just show that part in the screen and move it slowly to the right till the end of the image. Achieving a "scroll" effect across the image.
I have been looking in the website and internet last days and I just found the library of PanoramicGL or some ways to watch 360ยบ images.
This Is For Scroll Click Here
You must use PanoramaClient (which is part of Google Play Services) to open PhotoSphere photos.
An example of how to do this can be found on this Android developer blog post:
// This listener will be called with information about the given panorama.
OnPanoramaInfoLoadedListener infoLoadedListener =
new OnPanoramaInfoLoadedListener() {
#Override
public void onPanoramaInfoLoaded(ConnectionResult result,
Intent viewerIntent) {
if (result.isSuccess()) {
// If the intent is not null, the image can be shown as a
// panorama.
if (viewerIntent != null) {
// Use the given intent to start the panorama viewer.
startActivity(viewerIntent);
}
}
// If viewerIntent is null, the image is not a viewable panorama.
}
};
// Create client instance and connect to it.
PanoramaClient client = ...
...
// Once connected to the client, initiate the asynchronous check on whether
//the image is a viewable panorama.
client.loadPanoramaInfo(infoLoadedListener, panoramaUri);
Thanks to kishu, I made my own method to animate a panoramic image dynamically depending if its in landscape or portrait mode.
You can ignore the orientation value of the method, I only use it to change the animation of the video from X to Y if I want to see the image in landscape.
public void animatePanorama(int orientation) {
int duration;
// The milisecons that we will use dinamically for the animation, been this is 1,31milisecons for pixel
float miliseconsPixel = 1.31f;
float imageWidth;
//Delta X and Y values for the animation
float deltaX = 0f;
float deltaY = 0f;
float aspectRatio;
//We get the drawable from the container to calcule his real Width and Height
final Drawable d = mImageContainer.getDrawable();
final int origWidth = d.getIntrinsicWidth();
final int origHeight = d.getIntrinsicHeight();
//With that we get the real aspect ratio and a duration
if (origWidth > origHeight) {
aspectRatio = (float) origWidth / (float) origHeight;
duration = (int) (miliseconsPixel * origWidth);
imageWidth = mImageContainer.getMeasuredHeight() * aspectRatio;
} else {
aspectRatio = (float) origHeight / (float) origWidth;
duration = (int) (miliseconsPixel * origHeight);
imageWidth = mImageContainer.getMeasuredWidth() * aspectRatio;
}
//Set if the animation will be horizontal(Portrait) or Vertical(landscape)
if (orientation == 0 || orientation == 180)
deltaX = imageWidth / 2f - mImageContainer.getMeasuredWidth() / 2;
else
deltaY = imageWidth / 2f - mImageContainer.getMeasuredHeight() / 2;
//New Animation
Animation animation = new TranslateAnimation(deltaX, -deltaX, deltaY, -deltaY);
//Add Duration
animation.setDuration(duration);
animation.setFillAfter(true);
//Add cycle for repeating mode
animation.setRepeatCount(-1);
animation.setRepeatMode(Animation.REVERSE);
mImageContainer.startAnimation(animation);
}
I am developing game with libgdx and i got stuck with aspect ratio on different devices.
After a lot of thinking i figured that following is best solution for the problem:
I want to have camera always fixed to 16:9 aspect ratio and draw everything using that camera
If a device aspect is for example 4:3 i want to show only part of the view, not to strech it.
it should look something like this
blue is virtual screen(camera viewport) and red is device screen(visible area to 4:3 devices)
If for example device screen is also 16:9 full view should be visible.
Problem is i don't know how to achieve this.
I've done this for portrait screens, leaving some blank spaces at the top and bottom. As you can see in the following picture, the game stays at a 4:3 ratio and leaves whatever is leftover blank.
The content is always centered, and keeps its aspect ratio by not stretching the content unevenly. So here is some sample code Im using to achieve it.
public static final float worldW = 3;
public static final float worldH = 4;
public static OrthographicCamera camera;
...
//CALCULATING THE SCREENSIZE
float tempCalc = Gdx.graphics.getHeight() * GdxGame.worldW / Gdx.graphics.getWidth();
if(tempCalc < GdxGame.worldH){
//Adjust width
camera.viewportHeight = GdxGame.worldH;
camera.viewportWidth = Gdx.graphics.getWidth() * GdxGame.worldH / Gdx.graphics.getHeight();
worldWDiff = camera.viewportWidth - GdxGame.worldW;
}else{
//Adjust Height
camera.viewportHeight = tempCalc;
camera.viewportWidth = GdxGame.worldW;
worldHDiff = camera.viewportHeight - GdxGame.worldH;
}
camera.position.set(camera.viewportWidth/2f - worldWDiff/2f, camera.viewportHeight/2f - worldHDiff/2f, 0f);
camera.zoom = 1f;
camera.update();
I'm sure im not proposing the perfect solution, but you can play with the values on how the camera position and viewports are calculated so you can achieve the desired effect. Better than nothing I guess.
Also, Clash Of The Olympians Developers talk about how to achieve something like it and still make it look good on different devices (it is really interesting, but there is no code though): Our solution to handle multiple screen sizes in Android - Part one
The newer versions of libGDX provides a wrapper for glViewport called Viewport.
Camera camera = new OrthographicCamera();
//the viewport object will handle camera's attributes
//the aspect provided (worldWidth/worldHeight) will be kept
Viewport viewport = new FitViewport(worldWidth, worldHeight, camera);
//your resize method:
public void resize(int width, int height)
{
//notice that the method receives the entire screen size
//the last argument tells the viewport to center the camera in the screen
viewport.update(width, height, true);
}
I have written a function which works with different sizes of screen and images. The image might be zoomed and translated if it's possible.
public void transformAndDrawImage(SpriteBatch spriteBatch, Texture background, float scl, float offsetX, float offseY){
float width;
float height;
float _offsetX;
float _offsetY;
float bh2sh = 1f*background.getHeight()/Gdx.graphics.getHeight();
float bw2sw = 1f*background.getWidth()/Gdx.graphics.getWidth();
float aspectRatio = 1f*background.getHeight()/background.getWidth();
if(bh2sh>bw2sw){
width = background.getWidth() / bw2sw * scl;
height = width * aspectRatio;
}
else{
height = background.getHeight() / bh2sh * scl;
width = height / aspectRatio;
}
_offsetX = (-width+Gdx.graphics.getWidth())/2;
_offsetX += offsetX;
if(_offsetX-Gdx.graphics.getWidth()<=-width) _offsetX=-width+Gdx.graphics.getWidth();
if(_offsetX>0) _offsetX=0;
_offsetY = (-height+Gdx.graphics.getHeight())/2;
_offsetY += offseY;
if(_offsetY-Gdx.graphics.getHeight()<=-height) _offsetY=-height+Gdx.graphics.getHeight();
if(_offsetY>0) _offsetY=0;
spriteBatch.draw(background, _offsetX, _offsetY, width, height);
}
How to use it? It's easy:
#Override
public void render(float delta) {
Gdx.graphics.getGL10().glClearColor( 0.1f, 0.1f, 0.1f, 1 );
Gdx.graphics.getGL10().glClear( GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT );
spriteBatch.setProjectionMatrix(cam.combined);
spriteBatch.begin();
//zoom the image by 20%
float zoom = 1.2f; //Must be not less than 1.0
//translating the image depends on a few parameters such as zooming, aspect ratio of screen and image
offsetX+=0.1f; //offset the image to the left, if it's possible
offsetY+=0.1f; //offset the image to the bottom, if it's possible
transformAndDrawImage(spriteBatch, background, zoom, offsetX, offsetY);
//draw something else...
spriteBatch.end();
}
I'm working on an app where we hand rolled some star maps. So I don't have to talk in the abstract, here is the app in question: https://play.google.com/store/apps/details?id=com.tw.fireballs
If you look on the store listing, you can see we use an image just above the horizon...mostly because it looks super pretty. It's not an issue on lower resolution devices, they don't seem to suffer a huge issue rendering it due to lower number of pixels involved. On a higher resolution device like my HTC One or my wifes Nexus 5, there is a big framerate drop when it's on the screen. It's not bad enough to prevent me releasing it, but I'd like to improve it if possible.
I'm currently just using a SurfaceView, and drawing to a canvas acquired by mSurfaceHolder.lockCanvas(null), so it's not hardware accelerated. I tried implementing it as a regular view which is, but overall it actually went slower, so before I take the plunge into OpenGL land I want to explore if there is something I can do to speed this up.
Essentially, we start with a thin (opaque) image "slice" through the horizon, scale it up to the size of the diagonal of the screen and rotate it around to match the orientation of the device.
The drawing code is as follows:
private void loadResources() {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.RGB_565;
mHorizonImage = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.star_map_background, options);
}
#Override
public void updateDimensions(int width, int height) {
super.updateDimensions(width, height);
int horizonHeight = mCanvasHeight / 3;
int horizonWidth = (int) Math.sqrt(Math.pow(mCanvasHeight, 2) + Math.pow(mCanvasWidth, 2));
mHorizonImage = Bitmap.createScaledBitmap(mHorizonImage, horizonWidth, horizonHeight, false);
}
#Override
public void drawOn(Canvas canvas) {
double upScreen = -mProjection.distanceFromScreen * Math.tan(Math.toRadians(mOrientation.elevation));
double rightWithTiltCheat = upScreen * Math.sin(Math.toRadians(mOrientation.tilt));
double upWithTiltCheat = upScreen * Math.cos(Math.toRadians(mOrientation.tilt));
float x = (float) (mCanvasWidth / 2 * (1 + rightWithTiltCheat / mProjection.screenWidthInCm));
float y = (float) (mCanvasHeight / 2 * (1 - upWithTiltCheat / mProjection.screenHeightInCm));
canvas.save();
canvas.translate(x, y);
canvas.rotate((float) mOrientation.tilt);
canvas.drawBitmap(mHorizonImage, -mHorizonImage.getWidth() / 2, -mHorizonImage.getHeight(), null);
canvas.restore();
}
Is there a more efficient way to do this that won't be so affected by screen resolution? We've bandied around a few ideas, but I'd be keen to hear from someone who knows this stuff better than I. If you have any questions, please ask, I'd be grateful for any assistance.
Cheers,
Nathan
#pskink hit the nail on the head. Drawing the bitmap with a Matrix param is much more performant than the scaled bitmap and canvas rotation I was experiencing. On 1080P devices like my HTC One I used to watch the frame rate drop from 50+ to ~10 if I held the phone on a diagonal. Now I'd be lucky if it drops 5.
The modified code now looks like:
#Override
public void updateDimensions(int width, int height) {
super.updateDimensions(width, height);
mHorizonHeight = mCanvasHeight / 3;
mHeightScale = (float)mHorizonHeight / (float)mHorizonImage.getHeight();
mHorizonWidth = (int) Math.sqrt(Math.pow(mCanvasHeight, 2) + Math.pow(mCanvasWidth, 2));
mWidthScale = (float)mHorizonWidth / (float)mHorizonImage.getWidth();
}
#Override
public void drawOn(Canvas canvas) {
double upScreen = -mProjection.distanceFromScreen * Math.tan(Math.toRadians(mOrientation.elevation));
double rightWithTiltCheat = upScreen * Math.sin(Math.toRadians(mOrientation.tilt));
double upWithTiltCheat = upScreen * Math.cos(Math.toRadians(mOrientation.tilt));
float x = (float) (mCanvasWidth / 2 * (1 + rightWithTiltCheat / mProjection.screenWidthInCm));
float y = (float) (mCanvasHeight / 2 * (1 - upWithTiltCheat / mProjection.screenHeightInCm));
mDrawMatrix.reset();
mDrawMatrix.postScale(mWidthScale, mHeightScale);
mDrawMatrix.postTranslate(x - mHorizonWidth / 2, y - mHorizonHeight);
mDrawMatrix.postRotate((float) mOrientation.tilt, x, y);
canvas.drawBitmap(mHorizonImage, mDrawMatrix, null);
canvas.save();
}
I am loading PDF file via MUPDF and i added feature like brightness. I found bit difficult to increase the font size and highlight some text in the loaded pdf can anybody suggest on which file i we have set size and text color. Any help is appreciated i am following https://github.com/bhavyahmehta/Pdf-Reader---Writer/blob/master/Pdf_%20Reader_Writer/README.md. Below is the code where i am setting font size.
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
System.out.println("canvas");
float scale = mSourceScale*(float)getWidth()/(float)mSize.x;
//Typeface tf = Typeface.create("Helvetica",Typeface.BOLD);
Paint paint = new Paint();
//paint.setStyle((Style) PDFPaint.Style);
//paint.setTypeface(tf);
//canvas.drawText(scale,0,0,paint);
paint.setStrokeWidth(1);
paint.setAntiAlias(true);
paint.setTextSize(100);
}
Try to change in below method which you can find in ReaderView class
private void measureView(View v) {
// See what size the view wants to be
v.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
if (!mReflow) {
// Work out a scale that will fit it to this view
float scale = Math.min((float) getWidth() / (float) v.getMeasuredWidth(),(float) getHeight() / (float) v.getMeasuredHeight());
// Use the fitting values scaled by our current scale factor
v.measure(MeasureSpec.AT_MOST | (int) (v.getMeasuredWidth() * scale * mScale), MeasureSpec.AT_MOST | (int) (v.getMeasuredHeight() * (scale+0.6f) * mScale));
} else {
v.measure(View.MeasureSpec.EXACTLY | (int) (v.getMeasuredWidth()),
View.MeasureSpec.EXACTLY | (int) (v.getMeasuredHeight()));
}
}