iOS WebViewでwebp形式の画像を使用する方法


webpフォーマットのピクチャー
webpフォーマットの写真はgoogleが発表したもので、jpg pngよりも大きな利点があります。同じ品質の写真webp形式の写真は空間を占有するのがもっと小さいです。電気商のように写真が多いアプリでwebp形式の写真を使うのが有利です。
ことばを引く
以前から私たちのプロジェクトではwebp形式を採用していましたが、webView自体はwebp形式を解析できないので、webViewに基づく文章の詳細ページはこの最適化には使えませんでした。 
何か実現できる方法がありますか?もちろんあります。
技術解説を開始する前に、まず説明したいのですが、本稿の技術案は、本プロジェクトの状況に基づいています。文章の本文の大部分はインターフェースを通じて直接に入手し、クライアントの現地でhtml本文を組み立てることによって、最後にwebViewのloadHTMLString方法によって加載表示されます。一般的な写真は、リンクを変換してwebpサーバから対応するwebp版の画像を取得することができます。
本プロジェクトでは、ピクチャキャッシュはSDWebImageを使用し、webpサポート機能を起動しています。詳細ページwebViewに対する処理もこれに基づいて実現されます。 
考えてみると、案は実は比較的に明確で、これまでの写真のリンクを交換して、クライアントを通じてwebp写真をダウンロードして、jsを通じてページの上の下で完成した写真を更新しますが、実際に開発してもいくつかのピットに遭遇しました。
  • HTML解析ライブラリのsetAttributeNamedは属性
  • を増やすことができません。
  • webpサーバの画像をダウンロードした後のデフォルトキャッシュの場合、gifは正常に
  • を格納できません。
  • ダウンロードされた画像は、直ちにjsを通じてsrcをローカルファイルアドレスに変更して読み込むことができません。

  • 最終的な技術実現:
    1.ダウンロードしてきたhtmlコンテンツを処理し、すべての写真リンクを取得し、webpリンク処理を行います。 
    html内容の解析処理にはObjective-C-HMT-Parsserを使用していますが、このライブラリは長年メンテナンスしていません。ここに私のforkがあります。一部最適化の調整を行ったバージョンです。https://github.com/YueRuo/Objective-C-HMTL-Parser ( ローカルダウンロード
    画像の核心処理ロジックコード:
    
    @try {
     HTMLParser *parser = [[HTMLParser alloc] initWithString:htmlContent error:&error];
     HTMLNode *bodyNode = [parser body];
     if (error) {
     return;
     }
     //     img  
     NSArray *inputNodes = [bodyNode findChildTags:@"img"];
    
     for (HTMLNode *inputNode in inputNodes) {
     NSString *imageSrc = [inputNode getAttributeNamed:@"src"];
     if (!imageSrc) {
      continue;
     }
     NSString *newSrc = [[GlobalVariable shareInstance] resizeWebpImageWithUrl:imageSrc size:CGSizeMake((SCREEN_WIDTH - 20) * 2, 0)];//     ,  webp          ,   webp     
     //        
     NSString *key = [[SDWebImageManager sharedManager] cacheKeyForURL:[NSURL URLWithString:newSrc]];
     NSString *localPath = [[SDImageCache sharedImageCache] defaultCachePathForKey:key];
     NSString *webpImage = newSrc;
     BOOL localExsit = [[NSFileManager defaultManager] fileExistsAtPath:localPath];
     if (localExsit) {
      newSrc = [NSString stringWithFormat:@"file://%@", localPath];
     }
     //    webp      ,  newSrc webp             
     [_webpImageUrlDic setObject:webpImage forKey:newSrc];
     if(localExsit){
      setAttributeNamed(inputNode->_node, "src", [newSrc cStringUsingEncoding:NSUTF8StringEncoding]);
     }else{
      setAttributeNamed(inputNode->_node, "src", "      @2x.png");
     }
     // img        osrc   ,      
     setAttributeNamed(inputNode->_node, "osrc", [newSrc cStringUsingEncoding:NSUTF8StringEncoding]);
     }
     htmlContent = [NSMutableString stringWithString:parser.doc.rawContents];
    }
    @catch (NSException *exception) {
    }
    @finally {
     [webView loadHTMLString:htmlContent baseURL:baseUrl];
    }
    2.オリジナルの方法でwebp写真をダウンロードし、ローカルにキャッシュします。 
    ダウンロード後はjpgまたはpng形式として保存されますので、webViewでローカルローディングができますが、gifの保存には特別な処理が必要です。 
    また、実験によって、直接jsを通じて現地の画像にリアルタイムに更新できなくなり、写真のbase 64 encodeデータローディング方式で実現するしかない。 
    具体的なコードは以下の通りです。
    
    - (void)webViewDidFinishLoad:(UIWebView *)web {
     //  webp    
     [_webpImageUrlDic enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) {
     if([obj isEqualToString:key]){//        ,     
      [[SDWebImageDownloader sharedDownloader] downloadImageWithURL:[NSURL URLWithString:obj] options:0 progress:nil completed:^(UIImage *image, NSData *data, NSError *error, BOOL finished) {
      if (image&&finished) {
       NSString *js;
       NSRange range = [[obj lowercaseString] rangeOfString:@".gif"];//     gif
       BOOL isGif = (range.location != NSNotFound);
       if (!isGif) {
       [[SDImageCache sharedImageCache] storeImage:image forKey:obj];
       NSString *base64 = [UIImageJPEGRepresentation(image,1) base64EncodedStringWithOptions:0];
       js = [NSString stringWithFormat:@"replaceWebPImg('%@','data:image/jpeg;base64,%@')",key,base64];
       }else{//gif         ,   jpg      ,       
       [[SDImageCache sharedImageCache] storeImage:image recalculateFromImage:false imageData:data forKey:key toDisk:true];
       NSString *base64 = [data base64EncodedStringWithOptions:0];
       js = [NSString stringWithFormat:@"replaceWebPImg('%@','data:image/gif;base64,%@')",key,base64];
       }
       [NSThread excuteInMainThread:^{
       [webView stringByEvaluatingJavaScriptFromString:js];
       } async:false];
      }
      }];
     } else {//     ,       
      NSString *js;
      NSRange range = [[obj lowercaseString] rangeOfString:@".gif"];//     gif
      NSData* data = [NSData dataWithContentsOfFile:[key stringByReplacingOccurrencesOfString:@"file://" withString:@""]];
      NSString *base64 = [data base64EncodedStringWithOptions:0];
      BOOL isGif = (range.location != NSNotFound);
      if (!isGif) {
      js = [NSString stringWithFormat:@"replaceWebPImg('%@','data:image/jpeg;base64,%@')",obj,base64];
      }else{
      js = [NSString stringWithFormat:@"replaceWebPImg('%@','data:image/gif;base64,%@')",obj,base64];
      }
      [NSThread excuteInMainThread:^{
      [webView stringByEvaluatingJavaScriptFromString:js];
      } async:false];
     }
     }];
    } 
    3.webViewページに戻り、ローカルリンクで既存の画像を置き換える 
    ダウンロードした画像をロードします。ここでは主にjsによって実現されます。すなわち、第2ステップのreplace WebPImg方法は、先にhtmlのテンプレートに置くか、またはwebView DidFinishLoadによってjsを用いて注入されます。
    
    replaceWebPImg = function(src, localPath) {
     var imgs = document.querySelectorAll('img[osrc="'+src+'"]'),len = imgs.length;;
     for (var i = 0; i < len; i++) {
     var img = imgs[i];
     img.src = localPath;
     }
    }
    もう一度全体の流れをまとめてみましょう。
  • は、サーバから返されたhttylContentデータを対応して処理し、ピクチャがキャッシュされているかどうかを確認し、存在する場合はローカルアドレスをsrcとし、存在しない場合はピクチャのsrcをビットマップに置き換える。画像の住所を記録し、属性を追加してマークします。
  • ピクチャのアドレスはwebp変換され、クライアントを介して
  • をダウンロードする。
  • ダウンロード後の画像は、js方式によりsrc変更され、割り当てられたbase 64のピクチャ符号化データは、ローカルアドレスにリアルタイムでは表示されないため、
  • この文章は比較的簡単で、もっと詳しい手順は上のコードを調べてください。中にはまだ詳しいコメントを入れています。webViewでwebp写真を使いたい人に役に立ちます。
    締め括りをつける
    以上はこの文章の全部の内容です。本文の内容は皆さんの学習や仕事に対して一定の参考となる学習価値を持っています。質問があれば、メッセージを書いて交流してください。ありがとうございます。