Ответ 1
Хорошо, я думаю, что понял это. Было несколько штук в пресловутой загадке, и я благодарю @kcoppock за понимание, которое помогло мне решить некоторые из этих проблем.
Во-первых, вам нужно учитывать ориентацию при определении размера предварительного просмотра. Например, getOptimalPreviewSize()
из CameraPreview
of ApiDemos
не обращает внимания на ориентацию, просто потому, что их версия этого приложения имеет ориентацию, привязанную к ландшафту. Если вы хотите, чтобы ориентация плавала, вам нужно изменить целевой формат изображения для соответствия. Итак, где getOptimalPreviewSize()
имеет:
double targetRatio=(double)width / height;
вам также необходимо:
if (displayOrientation == 90 || displayOrientation == 270) {
targetRatio=(double)height / width;
}
где displayOrientation
- значение от 0 до 360, что я определяю примерно из 100 строк какого-то серьезного уродливого кода, поэтому я обертываю все это в повторно используемый компонент, который я опубликую в ближайшее время. Этот код основан на setDisplayOrientation()
JavaDocs и fooobar.com/questions/104416/....
(Кстати, если вы читаете это после 1 июля 2013 года, и вы не видите ссылку в этом ответе на этот компонент, напишите комментарий, чтобы напомнить мне, как я забыл)
Во-вторых, вы должны учитывать эту ориентацию дисплея при управлении соотношением сторон SurfaceView
/TextureView
, которое вы используете. Операция CameraPreview
от ApiDemos
имеет свой собственный Preview
ViewGroup
, который обрабатывает соотношение сторон, и вам нужно отменить соотношение сторон для использования в портрете:
if (displayOrientation == 90
|| displayOrientation == 270) {
previewWidth=mPreviewSize.height;
previewHeight=mPreviewSize.width;
}
else {
previewWidth=mPreviewSize.width;
previewHeight=mPreviewSize.height;
}
где displayOrientation
- это то же значение (90
и 270
как портретный, так и обратный портрет соответственно), и обратите внимание, что я не пытался работать с обратным портретом или обратным пейзажем, поэтому может быть требуется большая настройка).
Третий - и тот, который я нахожу в ярости - вы должны запустить предварительный просмотр перед вызовом setPictureSize()
на Camera.Parameters
. В противном случае, как будто соотношение сторон изображения применяется к кадрам предварительного просмотра, закручивая вещи вверх.
Поэтому у меня был код, похожий на следующий:
Camera.Parameters parameters=camera.getParameters();
Camera.Size pictureSize=getHost().getPictureSize(parameters);
parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
parameters.setPictureSize(pictureSize.width, pictureSize.height);
parameters.setPictureFormat(ImageFormat.JPEG);
camera.setParameters(parameters);
camera.startPreview();
и это неправильно. Что вам действительно нужно:
Camera.Parameters parameters=camera.getParameters();
Camera.Size pictureSize=getHost().getPictureSize(parameters);
parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
camera.setParameters(parameters);
camera.startPreview();
parameters=camera.getParameters();
parameters.setPictureSize(pictureSize.width, pictureSize.height);
parameters.setPictureFormat(ImageFormat.JPEG);
camera.setParameters(parameters);
Без этого изменения у меня получилось бы растянутое соотношение сторон, даже в ландшафте. Это не было проблемой для CameraPreview
of ApiDemos
, поскольку они не фотографировали, поэтому они никогда не вызывали setPictureSize()
.
Но пока, на Nexus 4, теперь у меня есть квадратные пропорции для портрета и пейзажа с плавающей ориентацией (т.е. не закрытой для пейзажа).
Я попытаюсь не забыть изменить этот вопрос, если я столкнусь с другими хаками, требуемыми другими устройствами, а также для ссылки на мои компоненты CameraView
/CameraFragment
, когда они будут выпущены.
ОБНОВЛЕНИЕ # 1
Ну, конечно, это не могло быть почти таким простым.: -)
Исправление проблемы, в которой setPictureSize()
закручивает соотношение сторон, работает... пока вы не сделаете снимок. В этот момент предварительный просмотр переключается на неправильное соотношение сторон.
Одной из возможностей было бы ограничить изображения теми, у кого одинаковое (или очень близкое) соотношение сторон к просмотру, поэтому икота не существует. Мне не нравится этот ответ, так как пользователь должен иметь возможность получать любой размер изображения, предлагаемый камерой.
Вы можете ограничить объем ущерба тем, что:
- Только обновление размера изображения и т.д.
Camera.Parameters
непосредственно перед съемкой - Возврат к предварительному снимку
Camera.Parameters
после съемки
Это все еще отражает неправильное соотношение сторон в моменты, когда изображение выполняется. Долгое решение для этого - я думаю, - временно заменить предварительный просмотр камеры неподвижным изображением (последний кадр предварительного просмотра) во время съемки. Я попробую это в конце концов.
UPDATE # 2: v0.0.1 теперь доступна моя библиотека CWAC-камеры, в которую вошли вышеупомянутые код.