简体   繁体   English

如何在角度上修复照片方向

[英]How to fix photo orientation on angular

I'm having trouble getting photos to orient the correct way in my angular/node app.我在获取照片以在我的 angular/node 应用程序中以正确的方式定位时遇到问题。

My app is set up so that I use ng2-file-upload to send the file from the angular app to the server where multer and multer-s3 saves that photo in AWS S3.我的应用程序已设置好,以便我使用 ng2-file-upload 将文件从 angular 应用程序发送到 multer 和 multer-s3 将该照片保存在 AWS S3 中的服务器。 I then save the filename in my postgres database and use it to call the photo by url.然后我将文件名保存在我的 postgres 数据库中,并使用它通过 url 调用照片。

My issue is, is the photo is uploaded by the iPhone (could be others I only tried iphone) and is returned rotated to the left.我的问题是,照片​​是由 iPhone 上传的(可能是我只试过 iphone 的其他照片)并返回到左侧旋转。

Ive looked into different options on the server side that have not worked for me.我研究了服务器端的不同选项,这些选项对我不起作用。 This includes the libraries fix-orientation and jpeg-autorotate.这包括库 fix-orientation 和 jpeg-autorotate。

Does anyone have a solution they've implemented on the client-side in Angular2+ ?有没有人有他们在 Angular2+ 的客户端实施的解决方案?

Here is my image-upload code on the server side这是我在服务器端的图片上传代码

aws.config.loadFromPath(path3);
var s3 = new aws.S3();
var fileName = '';
var uploadM = multer({
  storage: multerS3({
    s3: s3,
    bucket: 'XXX',
    acl: 'public-read',
    metadata: function (req, file, cb) {
      console.log(file);
      console.log(req.file);
      cb(null, {fieldName: file.fieldname});
    },
    key: function (req, file, cb) {
      fileName = Date.now().toString() + "-" + (Math.round(Math.random() * 10000000000000000)).toString() + '-' + file.originalname;
      cb(null, fileName)
    }
  })
});

router.post('/upload', uploadM.array('photo', 3), function(req,res) {
    if (res.error) {
      return res.status(400).json({
        message: "Error",
        error: res.error
      });
    }
    return res.status(200).send(fileName);

});


module.exports = router;

And here is my code on the angular app这是我在 angular 应用程序上的代码

  public uploader:FileUploader = new FileUploader({url: this.devUrl, itemAlias: 'photo'});

  constructor(
    private userS: UserService,
    private authS: MyAuthService,
    private router: Router,
    private itemS: ItemService,
    private uis: UiService) {}

  ngOnInit() {
    this.uploader.onAfterAddingFile = (file)=> { file.withCredentials = false; };

    this.uploader.onCompleteItem = (item:any, response:any, status:any, headers:any) => {
      this.awsUrls.push('AWSURL' + response);
      this.filesUploaded = true;
      this.uploaderLoading = false;
    };

  }

  addItem() {
    this.uploaderLoading = true;
    this.itemS.onNewItem(this.awsUrls)
      .subscribe(data => {
        this.uis.onFlash('Posted Successfully. Add Details!', 'success');
        this.itemS.onSetUpdateItemId(data.id, false);
        this.uploaderLoading = false;
        this.onPhotoAdded();
      }, resp => {
        this.uploaderLoading = false;
        this.uis.onFlash('Error Posting', 'error');
        console.log(resp);
      });
  }

  onUploadClicked() {
    this.uploader.uploadAll();
    this.uploaderLoading = true;
  }

Fix your image orientation issue by reading Exif data in angular.通过以角度读取 Exif 数据来修复您的图像方向问题。

Install exif-js安装 exif-js

npm i exif-js --save

Import EXIF to your component将 EXIF 导入您的组件

import * as EXIF from 'exif-js';

setImgOrientation methos has file param which is uploaded file object , inputBase64String will base64 string of that same file setImgOrientation 方法具有上传文件对象的文件参数inputBase64String将是同一文件的base64字符串

setImgOrientation(file, inputBase64String) {
 return new Promise((resolve, reject) => {
  const that = this;
  EXIF.getData(file, function () {
    if (this && this.exifdata && this.exifdata.Orientation) {
      that.resetOrientation(inputBase64String, this.exifdata.Orientation, function 
     (resetBase64Image) {
        inputBase64String = resetBase64Image;
        resolve(inputBase64String);
      });
    } else {
      resolve(inputBase64String);
    }
    });
   });
  }

  resetOrientation(srcBase64, srcOrientation, callback) {
  const img = new Image();

  img.onload = function () {
  const width = img.width,
    height = img.height,
    canvas = document.createElement('canvas'),
    ctx = canvas.getContext('2d');

  // set proper canvas dimensions before transform & export
  if (4 < srcOrientation && srcOrientation < 9) {
    canvas.width = height;
    canvas.height = width;
  } else {
    canvas.width = width;
    canvas.height = height;
  }

  // transform context before drawing image
  switch (srcOrientation) {
    case 2: ctx.transform(-1, 0, 0, 1, width, 0); break;
    case 3: ctx.transform(-1, 0, 0, -1, width, height); break;
    case 4: ctx.transform(1, 0, 0, -1, 0, height); break;
    case 5: ctx.transform(0, 1, 1, 0, 0, 0); break;
    case 6: ctx.transform(0, 1, -1, 0, height, 0); break;
    case 7: ctx.transform(0, -1, -1, 0, height, width); break;
    case 8: ctx.transform(0, -1, 1, 0, 0, width); break;
    default: break;
  }

  // draw image
  ctx.drawImage(img, 0, 0);

  // export base64
  callback(canvas.toDataURL());
};

  img.src = srcBase64;
}

In my oppinion, the ideal solution would be to rotate the images prior to sending them to S3 so that it is done only once (not every single time a user views an image).在我看来,理想的解决方案是在将图像发送到 S3 之前旋转图像,以便它只执行一次(不是每次用户查看图像时)。

You could use this librairy prior to uploading to S3 to ensure the images are in the corect orientation.您可以在上传到 S3 之前使用此库以确保图像处于正确方向。

Look at this sample , it could be integrated easily in your code without much effort.看看这个示例,它可以轻松地集成到您的代码中。

Regards,问候,

If it always happens to all iPhone images you can a column to your postgres table called iphone and set it to true when the photo is uploaded from an iPhone and then rotate it using CSS如果它总是发生在所有iPhone 图像上,您可以在 postgres 表中添加一个名为iphone的列,并在从 iPhone 上传照片时将其设置为 true,然后使用 CSS 旋转它

-webkit-transform: rotate(90deg);
-moz-transform: rotate(90deg);
-ms-transform: rotate(90deg);
-o-transform: rotate(90deg);
transform: rotate(90deg);

After messing with a couple of JS libraries and JS-based fixes.在搞乱了几个 JS 库和基于 JS 的修复之后。 I needed a fix for image-orientation in Angular 4 specifically.我需要专门修复 Angular 4 中的图像方向。 This is a workaround that I implemented that may help Angular developers searching for an answer.这是我实施的一种解决方法,可以帮助 Angular 开发人员寻找答案。

Basically, I added inputs during the upload process that asks the user if the device is an iPhone or iPhone landscape photo.基本上,我在上传过程中添加了输入,询问用户设备是 iPhone 还是 iPhone 风景照片。 With the iPhone and iPhoneLandscape booleans in my model, I set these variables to true if the user indicated that the photo was taken with either parameter.使用模型中的iPhoneiPhoneLandscape布尔值,如果用户指出照片是使用任一参数拍摄的,我将这些变量设置为 true。

On the client-side, I retrieved the item photo and used ngStyle to rotate the photo 90 degrees if item.iPhone was true and 180 degrees if item.iPhoneLandscape was true.在客户端,如果 item.iPhone 为真,我检索项目照片并使用 ngStyle 将照片旋转 90 度,如果 item.iPhoneLandscape 为真,则将照片旋转 180 度。

// For postgres users.... my item model item.mode.js // 对于 postgres 用户.... 我的项目模型 item.mode.js

module.exports = function(sequelize, DataTypes) {
  var Item = sequelize.define("Item", {
    photos: {
      type: DataTypes.ARRAY(DataTypes.STRING),
      allowNull: false
    },
    name: {
      type: DataTypes.STRING,
      isLowerCase: true,
      allowNull: true,
      defaultValue: null
    },
    description: {
      type: DataTypes.STRING,
      isLowerCase: true,
      allowNull: true,
      defaultValue: null
    },
    condition: {
      type: DataTypes.STRING,
      allowNull: true,
      defaultValue: null
    },
    price: {
      type: DataTypes.INTEGER,
      allowNull: true,
      defaultValue: null
    },
    interval: {
      type: DataTypes.INTEGER,
      allowNull: true,
      defaultValue: 1
    },
    category: {
      type: DataTypes.STRING,
      allowNull: true,
      defaultValue: null
    },
    negotiable: {
      type: DataTypes.BOOLEAN,
      allowNull: true,
      defaultValue: true
    },
    shipping: {
      type: DataTypes.BOOLEAN,
      allowNull: true,
      defaultValue: false
    },
    freeShipping: DataTypes.BOOLEAN,
    length: DataTypes.INTEGER,
    width: DataTypes.INTEGER,
    height: DataTypes.INTEGER,
    weight: DataTypes.INTEGER,
    unavailableDates: {
      type: DataTypes.ARRAY(DataTypes.RANGE(DataTypes.DATE)),
      allowNull: true,
      defaultValue: []
    },
    available: {
      type: DataTypes.BOOLEAN,
      allowNull: true,
      defaultValue: true
    },
    securityDeposit: {
      type: DataTypes.INTEGER,
      defaultValue: 0
    },
    iPhone: {
      type: DataTypes.BOOLEAN,
      defaultValue: false
    },
    iPhoneLandscape: {
      type: DataTypes.BOOLEAN,
      defaultValue: false
    }
  });

// my model on angular item.model.ts // 我的角度模型 item.model.ts

export class Item {
  constructor(
    public id?: number,
    public photos?: string[],
    public name?: string,
    public description?: string,
    public condition?: string,
    public price?: number,
    public interval?: number,
    public category?: string,
    public negotiable?: boolean,
    public shipping?: boolean,
    public length?: number,
    public width?: number,
    public height?: number,
    public weight?: number,
    public unavailableDates?: Date[],
    public available?: boolean,
    public iPhone?: boolean,
    public iPhoneLandscape?: boolean,
    public ownerId?: number,
    public owner?: object
  ) {}
}

// Calling the item from the server in my item.service.ts // 在我的 item.service.ts 中从服务器调用项目

  onReturnItems() {
    return this.http.get(this.devUrl)
      .map(data => {
        let items: Item[] = data['obj'];
        return items;
      })
      .shareReplay();
  }

// My style function calling the CSS object in item-list.component.ts // 我的样式函数调用 item-list.component.ts 中的 CSS 对象

  styleObject(s: string, item): Object {
     if (s === 'photo') {
      if (item.iPhone) {
        return {'-webkit-transform': 'rotate(90deg)',
          '-moz-transform': 'rotate(90deg)',
          '-ms-transform': 'rotate(90deg)',
          '-o-transform': 'rotate(90deg)',
          'transform': 'rotate(90deg)'}
      } else if (item.iPhoneLandscape) {
        return {'-webkit-transform': 'rotate(180deg)',
          '-moz-transform': 'rotate(180deg)',
          '-ms-transform': 'rotate(180deg)',
          '-o-transform': 'rotate(180deg)',
          'transform': 'rotate(180deg)'}
      }
    }

// And finally using ngStyle and ngFor in my template in item-list.component.html // 最后在 item-list.component.html 的模板中使用 ngStyle 和 ngFor

<div class="card column is-one-quarter" style="padding: 0; margin-left: 12px; margin-right: 12px;" *ngFor="let item of items">
          <div class="card-image"  (click)="onSetItemId(item.id)">
            <!--<iframe [src]="item.photos[0]"></iframe>-->
            <figure class="image" style="border-radius: 0;">
              <img [src]="item.photos[0]" alt="Image" [ngStyle]="styleObject('photo', item)"  *ngIf="itemsRetrieved" style="border-radius: 0;">
            </figure>
          </div>

Hopefully you can figure it out from this!希望你能从这里弄清楚! Good luck!祝你好运!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM