Camera orientation issue in Android
Asked Answered
L

15

101

I am building an application that uses camera to take pictures. Here is my source code to do this:

File file = new File(Environment.getExternalStorageDirectory(),
            imageFileName);
imageFilePath = file.getPath();
Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
// Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(file));
startActivityForResult(intent, ACTIVITY_NATIVE_CAMERA_AQUIRE);

On onActivityResult() method, I use BitmapFactory.decodeStream() to pickup the image.

When I run my application on Nexus one, it runs well. But when I run on Samsung Galaxy S or HTC Inspire 4G, the image's direction is not correct.

  • Capture with portrait mode, the real image (save on SD card) always rotates 90 degree.

image preview after shot real image on SD card

Image preview after shot --------- Real image on SD card

  • Capture with landscape mode, all things are good.

Image preview after shot Real image on SD card

Image preview after shot --------- Real image on SD card

Largent answered 20/5, 2011 at 8:7 Comment(5)
setRotation(90) did work for me in Samsung Galaxy Nexus, while it didn't rotate the image in Xperia S.Encage
can anyone help me with this? i have same problem #28379630Barela
#14066538Enharmonic
Answer here #14066538Enharmonic
Possible duplicate of Why does an image captured using camera intent gets rotated on some devices on Android?Jeremiahjeremias
M
54

Since you're not writing your own camera, I think it boils down to this:

some devices rotate the image before saving it, while others simply add the orientation tag in the photo's exif data.

I'd recommend checking the photo's exif data and looking particularly for

ExifInterface exif = new ExifInterface(SourceFileName); // Since API Level 5
String exifOrientation = exif.getAttribute(ExifInterface.TAG_ORIENTATION);

Since the photo is displaying correctly in your app, i'm not sure where the problem is, but this should definitely set you on the right path!

Maudmaude answered 25/5, 2011 at 12:21 Comment(12)
This doesn't seem to work on some devices, it returns 0 for all orientations.. I know it happens on Galaxy S Infuse and Sony Xperia Arc, and S II.. Interesting thing here is that when these same images are selected from gallery, the content provider has the proper orientation value.. Any ideas?Aguish
here sourcefilename actually the entire file pathWoodhouse
@TolgaE You are right. It returns 0 for some devices including DroidX. I am currently working on a solution. Not sure if it's going to work.Drescher
@Drescher Yes I tried to solve this (opened ticket with Android and so on) And i think I found a reasonable solution to handle both phones with proper and faulty orientation information. Check out my detailed answer I posted to my own question here; https://mcmap.net/q/50209/-images-taken-with-action_image_capture-always-returns-1-for-exifinterface-tag_orientation-on-some-gingerbread-devicesAguish
@Maudmaude I tried this solution to find. but it is returning 0 for all orientations. Do you have any idea why it is returning 0 for all orientation.Fisk
@Abhijit, have u got the solution, if yes,could u please share it?Lablab
@CrazyLearner sorry bro, this was so long ago that I can't even recall. I will let you know if I find something.Drescher
The reason for this solution not working is sometimes a wrong "path" used in ExifInterface constructor. Mostly on KitKat. See here, how to get the right path: https://mcmap.net/q/18043/-get-real-path-from-uri-android-kitkat-new-storage-access-framework-duplicateOrthodontics
It always returns 0 (ExifInterface.ORIENTATION_UNDEFINED) on my Samsung Galaxy S4...Balikpapan
Struggled for a while with rotation method since on some device when tacking photo in portrait mode simple rotation makes image stretched. The solution found was: code Matrix matrix = new Matrix(); matrix.postTranslate(-width / 2, -height / 2); matrix.postRotate(angle); matrix.postTranslate(width / 2, height / 2); Weeny
full & correct answer present here #6069622Enharmonic
At the case of adding orientation tag in the photo's exif data, the problem is when i try to edit image, the created bitmap is rotated. I have to look the exif data and rotate it into original. it's taking some time and also annoying.Pectoral
P
28

I used this to correct the orientation:

public void fixOrientation() {
    if (mBitmap.getWidth() > mBitmap.getHeight()) {
        Matrix matrix = new Matrix();
        matrix.postRotate(90);
        mBitmap = Bitmap.createBitmap(mBitmap , 0, 0, mBitmap.getWidth(), mBitmap.getHeight(), matrix, true);
    }
}

If the width of the Bitmap is greater than the height, the returned image is in landscape, so I rotate it 90 degrees.

Ptero answered 1/6, 2012 at 5:22 Comment(4)
What if the image was actually taken in landscape? Your code will still rotate it. This is not an answer to the question.Contempt
My application forces portrait, so that isn't an issue. I only included this here an alternative solution to the problem.Ptero
But if the application forces portrait you still can take a landscape picture (width > height) and it will be rotated... It's at least what I'm getting setting screenOrientation="portrait" for everything... camera still can take landscape pics.Sandiesandifer
full & correct answer present here #6069622Enharmonic
M
22

There are two things needed:

  1. Camera preview need the same as your rotation. Set this by camera.setDisplayOrientation(result);

  2. Save the picture captured as your camera preview. Do this via Camera.Parameters.

     int mRotation = getCameraDisplayOrientation();
    
     Camera.Parameters parameters = camera.getParameters();
    
     parameters.setRotation(mRotation); //set rotation to save the picture
    
     camera.setDisplayOrientation(result); //set the rotation for preview camera
    
     camera.setParameters(parameters);
    
Mcilroy answered 4/7, 2013 at 10:28 Comment(5)
this is it! Camera.parameters is really convenient to save snapshots without rendering to an intermediate bitmapDiaphone
Please mark this as the easiest answer! This do the job! Very happy about this easy solutionMaddeu
If this snippet is taken as is, we could just say parameters.setRotation(result), no?Spherule
This assumes you are using the Camera class directly, you aren't able to specify the same options when you are using the ACTION_IMAGE_CAPTURE intent.Kodok
What is result and getCameraDisplayOrientation()?Landonlandor
I
10
            int rotate = 0;
            try {
                File imageFile = new File(sourcepath);
                ExifInterface exif = new ExifInterface(
                        imageFile.getAbsolutePath());
                int orientation = exif.getAttributeInt(
                        ExifInterface.TAG_ORIENTATION,
                        ExifInterface.ORIENTATION_NORMAL);

                switch (orientation) {
                case ExifInterface.ORIENTATION_ROTATE_270:
                    rotate = 270;
                    break;
                case ExifInterface.ORIENTATION_ROTATE_180:
                    rotate = 180;
                    break;
                case ExifInterface.ORIENTATION_ROTATE_90:
                    rotate = 90;
                    break;
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            Matrix matrix = new Matrix();
    matrix.postRotate(rotate);
    bitmap = Bitmap.createBitmap(bitmap , 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
Impair answered 14/1, 2014 at 12:40 Comment(1)
it would be helpful to have some explanation what your code is doing, and how it is doing things differently than other answers (the question is after all already quite old, and the other answers therefore probably quite mature).Mayolamayon
C
8

Another option is to rotate the bitmap in the result screen like this:

ImageView img=(ImageView)findViewById(R.id.ImageView01);
Bitmap bmp = BitmapFactory.decodeResource(getResources(), R.drawable.refresh);
// Getting width & height of the given image.
int w = bmp.getWidth();
int h = bmp.getHeight();
// Setting post rotate to 90
Matrix mtx = new Matrix();
mtx.postRotate(90);
// Rotating Bitmap
Bitmap rotatedBMP = Bitmap.createBitmap(bmp, 0, 0, w, h, mtx, true);
BitmapDrawable bmd = new BitmapDrawable(rotatedBMP);

img.setImageDrawable(bmd);
Crofoot answered 14/9, 2011 at 9:50 Comment(2)
This approach won't work, as it also rotates images from devices that handles orientation properly.Rouvin
full & correct answer present here #6069622Enharmonic
P
3

I have also this type of same problem for some device:

private void rotateImage(final String path) {

    Bitmap scaledBitmap = Bitmap.createScaledBitmap(Conasants.bm1, 1000,
            700, true);
    Bitmap rotatedBitmap = null;
    try {
        ExifInterface ei = new ExifInterface(path);
        int orientation = ei.getAttributeInt(ExifInterface.TAG_ORIENTATION,
                ExifInterface.ORIENTATION_NORMAL);
        Matrix matrix = new Matrix();
        switch (orientation) {
        case ExifInterface.ORIENTATION_ROTATE_90:
            matrix.postRotate(90);
            rotatedBitmap = Bitmap.createBitmap(scaledBitmap, 0, 0,
                    scaledBitmap.getWidth(), scaledBitmap.getHeight(),
                    matrix, true);
            break;
        case ExifInterface.ORIENTATION_ROTATE_180:
            matrix.postRotate(180);
            rotatedBitmap = Bitmap.createBitmap(scaledBitmap, 0, 0,
                    scaledBitmap.getWidth(), scaledBitmap.getHeight(),
                    matrix, true);
            break;
        case ExifInterface.ORIENTATION_ROTATE_270:
            matrix.postRotate(270);
            rotatedBitmap = Bitmap.createBitmap(scaledBitmap, 0, 0,
                    scaledBitmap.getWidth(), scaledBitmap.getHeight(),
                    matrix, true);
            break;
        default:
            rotatedBitmap = Bitmap.createBitmap(scaledBitmap, 0, 0,
                    scaledBitmap.getWidth(), scaledBitmap.getHeight(),
                    matrix, true);
            break;
        }
    } catch (Throwable e) {
        e.printStackTrace();
    }
    cropImage.setImageBitmap(rotatedBitmap);
    rotatedBitmap = null;
    Conasants.bm1 = null;
}
Postnasal answered 7/10, 2014 at 13:33 Comment(0)
J
1

Try this way : static Uri image_uri; static Bitmap taken_image=null;

            image_uri=fileUri; // file where image has been saved

      taken_image=BitmapFactory.decodeFile(image_uri.getPath());
      try
        {
            ExifInterface exif = new ExifInterface(image_uri.getPath()); 

            int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);


            switch(orientation) {
                case ExifInterface.ORIENTATION_ROTATE_90:
                    taken_image=decodeScaledBitmapFromSdCard(image_uri.getPath(), 200, 200);
                    RotateBitmap(taken_image, 90);
                    break;
                case ExifInterface.ORIENTATION_ROTATE_180:
                    taken_image=decodeScaledBitmapFromSdCard(image_uri.getPath(), 200, 200);
                    RotateBitmap(taken_image, 180);

                    break;
                case ExifInterface.ORIENTATION_ROTATE_270:
                    taken_image=decodeScaledBitmapFromSdCard(image_uri.getPath(), 200, 200);
                    RotateBitmap(taken_image, 270);

                    break;
                case ExifInterface.ORIENTATION_NORMAL:
                    taken_image=decodeScaledBitmapFromSdCard(image_uri.getPath(), 200, 200);
                    RotateBitmap(taken_image, 0);

                    break;
            }

        }
        catch (OutOfMemoryError e)
        {
            Toast.makeText(getActivity(),e+"\"memory exception occured\"",Toast.LENGTH_LONG).show();


        }



public Bitmap RotateBitmap(Bitmap source, float angle) {
      Matrix matrix = new Matrix();
      matrix.postRotate(angle);

      round_Image = source;
      round_Image = Bitmap.createBitmap(source, 0, 0, source.getWidth(),   source.getHeight(), matrix, true);


  return Bitmap.createBitmap(source, 0, 0, source.getWidth(), source.getHeight(), matrix, true);

}

Joanajoane answered 16/4, 2014 at 10:41 Comment(0)
S
1

No more checking the photo's exif data. Go easy with Glide.

Google introduced us an Image Loader Library for Android developed by bumptech named Glide as a library that recommended by Google. It has been used in many Google open source projects till now including Google I/O 2014 official application.

Ex : Glide.with(context).load(uri).into(imageview);

For more : https://github.com/bumptech/glide

Selry answered 11/10, 2015 at 12:31 Comment(0)
T
1
public void setCameraPicOrientation(){
        int rotate = 0;
        try {
            File imageFile = new File(mCurrentPhotoPath);
            ExifInterface exif = new ExifInterface(
                    imageFile.getAbsolutePath());
            int orientation = exif.getAttributeInt(
                    ExifInterface.TAG_ORIENTATION,
                    ExifInterface.ORIENTATION_NORMAL);

            switch (orientation) {
                case ExifInterface.ORIENTATION_ROTATE_270:
                    rotate = 270;
                    break;
                case ExifInterface.ORIENTATION_ROTATE_180:
                    rotate = 180;
                    break;
                case ExifInterface.ORIENTATION_ROTATE_90:
                    rotate = 90;
                    break;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        Matrix matrix = new Matrix();
        matrix.postRotate(rotate);
        int targetW = 640;
        int targetH = 640;

        /* Get the size of the image */
        BitmapFactory.Options bmOptions = new BitmapFactory.Options();
        bmOptions.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(mCurrentPhotoPath, bmOptions);
        int photoW = bmOptions.outWidth;
        int photoH = bmOptions.outHeight;

        /* Figure out which way needs to be reduced less */
        int scaleFactor = 1;
        if ((targetW > 0) || (targetH > 0)) {
            scaleFactor = Math.min(photoW/targetW, photoH/targetH);
        }

        /* Set bitmap options to scale the image decode target */
        bmOptions.inJustDecodeBounds = false;
        bmOptions.inSampleSize = scaleFactor;
        bmOptions.inPurgeable = true;

        /* Decode the JPEG file into a Bitmap */
        Bitmap bitmap = BitmapFactory.decodeFile(mCurrentPhotoPath, bmOptions);
        bitmap= Bitmap.createBitmap(bitmap , 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
            /* Associate the Bitmap to the ImageView */
      imageView.setImageBitmap(bitmap);
    }

Hope this will help!! Thanks

Trimeter answered 23/1, 2017 at 6:15 Comment(0)
F
0
    public static  int mOrientation =  1;
    
    OrientationEventListener myOrientationEventListener;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);
        setContentView(R.layout.takephoto);
        
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
        
        
        myOrientationEventListener
        = new OrientationEventListener(getApplicationContext()) {
            
            @Override
            public void onOrientationChanged(int o) {
                // TODO Auto-generated method stub
                if(!isTablet(getApplicationContext()))
                {
                    if(o<=285 && o>=80)
                        mOrientation = 2;
                    else
                        mOrientation = 1;
                }
                else
                {
                    if(o<=285 && o>=80)
                        mOrientation = 1;
                    else
                        mOrientation = 2;
                }
                
            }
        };
        
        myOrientationEventListener.enable();
        
    }
    
    
    
    public static boolean isTablet(Context context) {
        return (context.getResources().getConfiguration().screenLayout
                & Configuration.SCREENLAYOUT_SIZE_MASK)
                >= Configuration.SCREENLAYOUT_SIZE_LARGE;
    }
    
}
Fishnet answered 12/5, 2014 at 5:20 Comment(0)
D
0

Just encounter the same issue here, the code snippet below works for me:

private static final String[] CONTENT_ORIENTATION = new String[] {
        MediaStore.Images.ImageColumns.ORIENTATION
};

static int getExifOrientation(ContentResolver contentResolver, Uri uri) {
    Cursor cursor = null;

    try {
        cursor = contentResolver.query(uri, CONTENT_ORIENTATION, null, null, null);
        if (cursor == null || !cursor.moveToFirst()) {
            return 0;
        }
        return cursor.getInt(0);
    } catch (RuntimeException ignored) {
        // If the orientation column doesn't exist, assume no rotation.
        return 0;
    } finally {
        if (cursor != null) {
            cursor.close();
        }
    }
}
Donela answered 18/9, 2014 at 8:8 Comment(0)
C
0

Try this in surfaceChanged callback:

Camera.Parameters parameters=mCamera.getParameters();
if(this.getResources().getConfiguration().orientation == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT){
    parameters.setRotation(90);
}else{
    parameters.setRotation(0);
}
mCamera.setParameters(parameters);
Cartload answered 26/1, 2015 at 10:28 Comment(0)
H
0

//button click

btnCamera.setOnClickListener( new View.OnClickListener() {
        @Override
        public void onClick(View view) {

                try {
                    ContentValues values;
                    values = new ContentValues();
                    values.put(MediaStore.Images.Media.TITLE, "New Picture");
                    values.put(MediaStore.Images.Media.DESCRIPTION, "From your Camera");
                    imageUri = context.getContentResolver().insert(
                            MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
                    Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                    intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
                    startActivityForResult(intent, CAMERA_REQUEST);
                }catch (Exception e){}

            });

//onActivityResult method

   if (requestCode==CAMERA_REQUEST){
        try {
            if (imageUri!=null) {
                path = String.valueOf(new File(FilePath.getPath(context, imageUri)));
                   }  
        }catch (Exception e){
            toast("please try again "+e.getMessage());
            Log.e("image error",e.getMessage());
        }
    }

//create a class filepath

public class FilePath {

public static String getPath(final Context context, final Uri uri) {

    // check here to KITKAT or new version
    final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;

    // DocumentProvider
    if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {

        // ExternalStorageProvider
        if (isExternalStorageDocument(uri)) {
            final String docId = DocumentsContract.getDocumentId(uri);
            final String[] split = docId.split(":");
            final String type = split[0];

            if ("primary".equalsIgnoreCase(type)) {
                return Environment.getExternalStorageDirectory() + "/"
                        + split[1];
            }
        }
        // DownloadsProvider
        else if (isDownloadsDocument(uri)) {

            final String id = DocumentsContract.getDocumentId(uri);
            final Uri contentUri = ContentUris.withAppendedId(
                    Uri.parse("content://downloads/public_downloads"),
                    Long.valueOf(id));

            return getDataColumn(context, contentUri, null, null);
        }
        // MediaProvider
        else if (isMediaDocument(uri)) {
            final String docId = DocumentsContract.getDocumentId(uri);
            final String[] split = docId.split(":");
            final String type = split[0];

            Uri contentUri = null;
            if ("image".equals(type)) {
                contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
            } else if ("video".equals(type)) {
                contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
            } else if ("audio".equals(type)) {
                contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
            }

            final String selection = "_id=?";
            final String[] selectionArgs = new String[] { split[1] };

            return getDataColumn(context, contentUri, selection,
                    selectionArgs);
        }
    }
    // MediaStore (and general)
    else if ("content".equalsIgnoreCase(uri.getScheme())) {

        // Return the remote address
        if (isGooglePhotosUri(uri))
            return uri.getLastPathSegment();

        return getDataColumn(context, uri, null, null);
    }
    // File
    else if ("file".equalsIgnoreCase(uri.getScheme())) {
        return uri.getPath();
    }

    return null;
}

/**
 * Get the value of the data column for this Uri. This is useful for
 * MediaStore Uris, and other file-based ContentProviders.
 *
 * @param context
 *            The context.
 * @param uri
 *            The Uri to query.
 * @param selection
 *            (Optional) Filter used in the query.
 * @param selectionArgs
 *            (Optional) Selection arguments used in the query.
 * @return The value of the _data column, which is typically a file path.
 */
public static String getDataColumn(Context context, Uri uri,
                                   String selection, String[] selectionArgs) {

    Cursor cursor = null;
    final String column = "_data";
    final String[] projection = { column };

    try {
        cursor = context.getContentResolver().query(uri, projection,
                selection, selectionArgs, null);
        if (cursor != null && cursor.moveToFirst()) {
            final int index = cursor.getColumnIndexOrThrow(column);
            return cursor.getString(index);
        }
    } finally {
        if (cursor != null)
            cursor.close();
    }
    return null;
}

/**
 * @param uri
 *            The Uri to check.
 * @return Whether the Uri authority is ExternalStorageProvider.
 */
public static boolean isExternalStorageDocument(Uri uri) {
    return "com.android.externalstorage.documents".equals(uri
            .getAuthority());
}

/**
 * @param uri
 *            The Uri to check.
 * @return Whether the Uri authority is DownloadsProvider.
 */
public static boolean isDownloadsDocument(Uri uri) {
    return "com.android.providers.downloads.documents".equals(uri
            .getAuthority());
}

/**
 * @param uri
 *            The Uri to check.
 * @return Whether the Uri authority is MediaProvider.
 */
public static boolean isMediaDocument(Uri uri) {
    return "com.android.providers.media.documents".equals(uri
            .getAuthority());
}

/**
 * @param uri
 *            The Uri to check.
 * @return Whether the Uri authority is Google Photos.
 */
public static boolean isGooglePhotosUri(Uri uri) {
    return "com.google.android.apps.photos.content".equals(uri
            .getAuthority());
}

}

Haddix answered 20/9, 2019 at 9:42 Comment(0)
M
-1

The code is functionally for landscape and portrait @frontCameraID = variable got it the method classic for show camera wanted

@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
    
    if(holder.getSurface() == null) {
        return;
    }
    try{
        camera.stopPreview();
    } catch (Exception e){
    }

    try{

        int orientation = getDisplayOrientation(frontCameraID);

        Camera.Parameters parameters = camera.getParameters();
        parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
        if (parameters.getSupportedFocusModes().contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {
            parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
        }

        parameters.setRotation(rotationPicture);
        camera.setParameters(parameters);
        camera.setDisplayOrientation(orientation);
        camera.startPreview();

    } catch (Exception e) {
        Log.i("ERROR", "Camera error changed: " + e.getMessage());
    }
}

Method for get orientation y rotation to save picture and display orientation @result = orientation on the preview view of camera @rotationPicture = rotation necessary to save picture correctly

private int getDisplayOrientation(int cameraId) {

    android.hardware.Camera.CameraInfo info = new android.hardware.Camera.CameraInfo();
    android.hardware.Camera.getCameraInfo(cameraId, info);
    int rotation = ((Activity) context).getWindowManager().getDefaultDisplay().getRotation();
    int degrees = 0;
    switch (rotation) {
        case Surface.ROTATION_0: degrees = 0; break;
        case Surface.ROTATION_90: degrees = 90; break;
        case Surface.ROTATION_180: degrees = 180; break;
        case Surface.ROTATION_270: degrees = 270; break;
    }

    int result;
    if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
        result = (info.orientation + degrees) % 360;
        result = (360 - result) % 360;
        rotationPicture = (360 - result) % 360;
    } else {
        result = (info.orientation - degrees + 360) % 360;
        rotationPicture = result;
    }

    return result;
}
Michaelamichaele answered 16/12, 2015 at 22:18 Comment(0)
H
-3

two One line solutions using Picasso and glide library

After spending a lot of time with a lot of solutions for image rotation problem I finally found two simple solutions. We don't need to do any additional works. Picasso and Glide are a very powerful library for handling images in your app includes. It will read image EXIF data and auto-rotates the images.

Using glide library https://github.com/bumptech/glide

Glide.with(this).load("http url or sdcard url").into(imgageView);

Using Picasso library https://github.com/square/picasso

Picasso.with(context).load("http url or sdcard url").into(imageView);
Holter answered 4/12, 2017 at 10:12 Comment(1)
Welcome to SO. Please refrain from asking for upvotes: meta.stackexchange.com/questions/194061/…Friedrick

© 2022 - 2024 — McMap. All rights reserved.