嗨,这是我旋转 jpeg 图像的方式:
private static boolean rotateJpg(String filepath, int degrees) {
// get current rotation degree
int iCurRotation = getExifOrientation(filepath);
// create exif
ExifInterface exif = null;
try {
exif = new ExifInterface(filepath);
} catch (IOException ex) {
return false;
}
// Calculate new rotation degree
int iNewRotation = iCurRotation + degrees;
try {
iNewRotation %= 360;
if (iNewRotation < 0) iNewRotation += 360;
int orientation = ExifInterface.ORIENTATION_NORMAL;
switch (iNewRotation) {
case 0:
orientation = ExifInterface.ORIENTATION_NORMAL;
break;
case 90:
orientation = ExifInterface.ORIENTATION_ROTATE_90;
break;
case 180:
orientation = ExifInterface.ORIENTATION_ROTATE_180;
break;
case 270:
orientation = ExifInterface.ORIENTATION_ROTATE_270;
break;
}
// save new rotation degree
if (exif != null) {
exif.setAttribute(ExifInterface.TAG_ORIENTATION, Integer.toString(orientation));
exif.saveAttributes();
}
} catch (Exception ex) {
return false;
}
return true;
}
上面的代码有效。但是,我有时会得到:
06-29 18:28:35.780: E/JHEAD(28163): Can't write back - didn't read all
我查了一下它是什么,发现是 external/jhead/jpgfile.c 抛出了错误:
// Command line parsing code
static const char * progname; // program name for error messages
//--------------------------------------------------------------------------
// Parse the marker stream until SOS or EOI is seen;
//--------------------------------------------------------------------------
static int ReadJpegSections (FILE * infile,ReadMode_t ReadMode)
{
int a;
int HaveCom = FALSE;
a = fgetc(infile);
if (a != 0xff || fgetc(infile) != M_SOI){
return FALSE;
}
for(;SectionsRead < MAX_SECTIONS-1;){
int itemlen;
int marker = 0;
int ll,lh, got;
uchar * Data;
for (a=0;a<7;a++){
marker = fgetc(infile);
if (marker != 0xff) break;
if (a >= 6){
printf("too many padding bytes\n");
return FALSE;
}
}
if (marker == 0xff){
// 0xff is legal padding, but if we get that many, something's wrong.
ErrExit("too many padding bytes!");
}
Sections[SectionsRead].Type = marker;
// Read the length of the section.
lh = fgetc(infile);
ll = fgetc(infile);
itemlen = (lh << 8) | ll;
if (itemlen < 2){
ErrExit("invalid marker");
}
Sections[SectionsRead].Size = itemlen;
Data = (uchar *)malloc(itemlen+1); // Add 1 to allow sticking a 0 at the end.
if (Data == NULL){
ErrExit("Could not allocate memory");
}
Sections[SectionsRead].Data = Data;
// Store first two pre-read bytes.
Data[0] = (uchar)lh;
Data[1] = (uchar)ll;
got = fread(Data+2, 1, itemlen-2, infile); // Read the whole section.
if (got != itemlen-2){
ErrExit("reading from file");
}
SectionsRead += 1;
//printf("Marker '%x' size %d\n",marker, itemlen);
switch(marker){
case M_SOS: // stop before hitting compressed data
// If reading entire image is requested, read the rest of the data.
if (ReadMode & READ_IMAGE){
int cp, ep, size;
// Determine how much file is left.
cp = ftell(infile);
fseek(infile, 0, SEEK_END);
ep = ftell(infile);
fseek(infile, cp, SEEK_SET);
size = ep-cp;
Data = (uchar *)malloc(size);
if (Data == NULL){
ErrExit("could not allocate data for entire image");
}
got = fread(Data, 1, size, infile);
if (got != size){
ErrExit("could not read the rest of the image");
}
Sections[SectionsRead].Data = Data;
Sections[SectionsRead].Size = size;
Sections[SectionsRead].Type = PSEUDO_IMAGE_MARKER;
SectionsRead ++;
HaveAll = 1;
}
return TRUE;
case M_EOI: // in case it's a tables-only JPEG stream
printf("No image in jpeg!\n");
return FALSE;
case M_COM: // Comment section
if (HaveCom || ((ReadMode & READ_EXIF) == 0)){
// Discard this section.
free(Sections[--SectionsRead].Data);
}else{
process_COM(Data, itemlen);
HaveCom = TRUE;
}
break;
case M_JFIF:
// Regular jpegs always have this tag, exif images have the exif
// marker instead, althogh ACDsee will write images with both markers.
// this program will re-create this marker on absence of exif marker.
free(Sections[--SectionsRead].Data);
break;
case M_EXIF:
if (SectionsRead <= 2){
// Seen files from some 'U-lead' software with Vivitar scanner
// that uses marker 31 later in the file (no clue what for!)
process_EXIF((char *)Data, itemlen);
}else{
// Discard this section.
free(Sections[--SectionsRead].Data);
}
break;
case M_SOF0:
case M_SOF1:
case M_SOF2:
case M_SOF3:
case M_SOF5:
case M_SOF6:
case M_SOF7:
case M_SOF9:
case M_SOF10:
case M_SOF11:
case M_SOF13:
case M_SOF14:
case M_SOF15:
process_SOFn(Data, marker);
break;
default:
// Skip any other unknown sections.
if (ShowTags){
printf("Unknown Jpeg section marker 0x%02x size %d\n",marker, itemlen);
}
break;
}
}
return TRUE;
}
//--------------------------------------------------------------------------
// Discard read data.
//--------------------------------------------------------------------------
void DiscardData(void)
{
int a;
for (a=0;a<SectionsRead;a++){
free(Sections[a].Data);
}
memset(&ImageInfo, 0, sizeof(ImageInfo));
SectionsRead = 0;
HaveAll = 0;
}
//--------------------------------------------------------------------------
// Read image data.
//--------------------------------------------------------------------------
int ReadJpegFile(const char * FileName, ReadMode_t ReadMode)
{
FILE * infile;
int ret;
infile = fopen(FileName, "rb"); // Unix ignores 'b', windows needs it.
if (infile == NULL) {
fprintf(stderr, "%s: can't open '%s'\n", progname, FileName);
return FALSE;
}
// Scan the JPEG headers.
ret = ReadJpegSections(infile, ReadMode);
if (!ret){
printf("Not JPEG: %s\n",FileName);
}
fclose(infile);
if (ret == FALSE){
DiscardData();
}
return ret;
}
//--------------------------------------------------------------------------
// Write image data back to disk.
//--------------------------------------------------------------------------
void WriteJpegFile(const char * FileName)
{
FILE * outfile;
int a;
if (!HaveAll){
ErrExit("Can't write back - didn't read all");
}
outfile = fopen(FileName,"wb");
if (outfile == NULL){
ErrExit("Could not open file for write");
}
// Initial static jpeg marker.
fputc(0xff,outfile);
fputc(0xd8,outfile);
if (Sections[0].Type != M_EXIF && Sections[0].Type != M_JFIF){
// The image must start with an exif or jfif marker. If we threw those away, create one.
static uchar JfifHead[18] = {
0xff, M_JFIF,
0x00, 0x10, 'J' , 'F' , 'I' , 'F' , 0x00, 0x01,
0x01, 0x01, 0x01, 0x2C, 0x01, 0x2C, 0x00, 0x00
};
fwrite(JfifHead, 18, 1, outfile);
}
// Write all the misc sections
for (a=0;a<SectionsRead-1;a++){
fputc(0xff,outfile);
fputc(Sections[a].Type, outfile);
fwrite(Sections[a].Data, Sections[a].Size, 1, outfile);
}
// Write the remaining image data.
fwrite(Sections[a].Data, Sections[a].Size, 1, outfile);
fclose(outfile);
}
我在线上遇到上述错误:
exif.saveAttributes();
得到这个错误是非常不一致的。此外,它甚至无法在 try/catch(Exception) 上捕获。我该如何解决?
提前致谢。