善良な若者が三頭蛇と戦った方法、またはAdobe InDesignドキュメントにSVGグラフィックスを埋め込む方法の物語-パート2

wiklequickによるこの投稿の続き。



ステップ5、またはワークスタイルで酒に酔ったマスターを適用する

さて、すでにプリミティブがあるので、色、アルファチャンネル、ラインスタイルを適用しましょう。



  private void applyStroke(Shape shape){
  ストロークストローク= getStroke();
  変換t = getTransform();
   if(stroke!= null){
     if(ストロークStroke instanceof BasicStroke){
       BasicStroke currStroke =(BasicStroke)ストローク;
       float [] ff = currStroke.getDashArray();
       if(ff!= null)setdash(ff.length、ff、currStroke.getDashPhase());
       float width =(float)(currStroke.getLineWidth()* Math.max(t.getScaleX()、t.getScaleY()));
       if(width <0.7f)width = 0.7f;
       setlinewidth(幅);
     }
    その他{
       setlinewidth(1.0f);
      形状strokedShape = stroke.createStrokedShape(shape);
      塗りつぶし(strokedShape);
     }
   }
  他に 
     setlinewidth(1.0f);
 }
A.

画像 一般にコードには複雑なものは含まれておらず、BasicStroke解析のみが含まれています。 それが何か他のものである場合、それはShapeの形で表現可能であり、そのように描くことができます。

次に、後続のシェイプのアルファレベルを取得し、InDesignに渡します。コードも非常に簡単です。



  private void applyAlpha(){
   float alpha = 1.0f;
  コンポジットcomp = getComposite();
   if(comp!= null && comp instanceof AlphaComposite){
     AlphaComposite alcomp =(AlphaComposite)comp;
     alpha = alcomp.getAlpha();
   }
   setopacity(alpha、true);
 } 
A.

しかし、カスタムペイントと複合材の場合、状況は非常に悲しくなります。 自分でラスタライズする必要があります。



  private boolean applyStyles(Shape shape){
  ペイントpaint = getPaint();
   if(paintinstance Color){
    カラーcc =(カラー)ペイント;
     setrgbcolor(cc.getRed()/ 255.0f、cc.getGreen()/ 255.0f、cc.getBlue()/ 255.0f);
     if(cc.getAlpha()!= 0 && cc.getAlpha()!= 255)setopacity(cc.getAlpha()/ 255.0f、true);
    それ以外の場合applyAlpha();
   }
   else if(paint!= null && shape!= null){
     applyAlpha();
     drawGradientAsBackground(形状、ペイント);
     falseを返します。
   }

  コンポジットcomp = getComposite();
   if(comp!= null && !!(compinstance of AlphaComposite)&& shape!= null){
     drawCustomComposite(shape、comp);
     falseを返します。
   }
   trueを返します。
 } 
A.

色の状況は非常に明白です(アルファチャネルを色に明示的に設定できることを除く)が、他のすべてには明確化が必要です。 関数はtrue / falseを返すことに注意してください。 Trueは、トリックが適用されなかったことを意味し、現在の形状は塗りつぶし()で描画する必要があります。 ただし、falseの場合、図形は既に画像としてラスタライズされており、画像の上に描画する必要はありません。

グラデーション自体は次のように描画する必要がありました。



  private void drawGradientAsBackground(形状、ペイントペイント){
   GraphicsConfiguration conf = getDeviceConfiguration();
   PaintContext pctx = paint.createContext(
     conf.getColorModel()、conf.getBounds()、shape.getBounds2D()、
     getTransform()、getRenderingHints());

  四角形r = getTransform()。CreateTransformedShape(形状).getBounds();
  ラスターラスター= pctx.getRaster(rx、ry、r.width、r.height);
   ColorModel cmodel = pctx.getColorModel();
   BufferedImage bfi =新しいBufferedImage(cmodel、raster.createCompatibleWritableRaster()、
     cmodel.isAlphaPremultiplied()、null);
   bfi.setData(ラスター);
  
   int [] argbBuf = getBuf(bfi、r.width、r.height);
   if(argbBuf!= null){
     applyClip(形状);
     drawImage(argbBuf、rx、ry、r.width、r.height、new AffineTransform());
     restoreClip();
   }
   pctx.dispose();
 } 
A.

この関数では、オフスクリーン画像にグラデーションが描画され、形状自体がクリッピング画像です。 同様に、非標準のCompositeをレンダリングします。



  private void drawCustomComposite(形状、複合コンポーネント){
  四角形r = getTransform()。CreateTransformedShape(形状).getBounds();
   BufferedImage bfi =新しいBufferedImage(r.width、r.height、BufferedImage.TYPE_INT_ARGB);
   Graphics2D g2 =(Graphics2D)bfi.getGraphics();
   g2.setTransform(getTransform());
   g2.setComposite(comp);
   g2.fill(形状);
   g2.dispose();
  
   int [] argbBuf = getBuf(bfi、r.width、r.height);
   if(argbBuf!= null){
     applyClip(形状);
     drawImage(argbBuf、rx、ry、r.width、r.height、new AffineTransform());
     restoreClip();
   }
 } 
A.

すでに変換された形状を描画しているため、drawImageで空のAffineTransformを設定します。



6番目のステップ、または敵を達成します

画像 最後に、私たちは最も興味深いことに到達しました。 他の場合、ネイティブ実装が本質的に単一行コードである場合、写真の場合はそうではありません。 最初に、画像をレンダリングするためのコードを示します。



  public boolean drawImage(Image img、int x、int y、int width、int height、Color bgcolor、ImageObserverオブザーバー){
   int [] argbBuf = getBuf(img、width、height);
   if(argbBuf == null)falseを返します。
    
   applyClip(getClip());
   applyAlpha();
   drawImage(argbBuf、x、y、幅、高さ、getTransform());
   restoreClip();
   trueを返します。
 } 
A.

コードは非常に単純です-クリッピング、アルファチャネルを設定し、ビットマトリックスを取得し、それをすべてInDesignに渡します。 ビットを取得することは明らかです。



  private int [] getBuf(画像img、int幅、int高さ){
   int [] argbBuf = new int [width * height];
   PixelGrabber pg =新しいPixelGrabber(img、0、0、幅、高さ、argbBuf、0、幅);
   {
     if(!pg.grabPixels())nullを返します。
   }
   catch(InterruptedException e){nullを返します。  }
   if((pg.getStatus()&ImageObserver.ABORT)!= 0)nullを返す;
   return argbBuf;
 } 
A.

ただし、InDesignへの転送にはいくつかの機能があります。 それらを考慮してください。



  private void drawImage(int [] argbBuf、int x、int y、int width、int height、AffineTransform変換){
   double [] transMatr = new double [6];
   transform.getMatrix(transMatr);
   this.image(argbBuf、x、y、幅、高さ、transMatr);
 } 
A.

これは、変換マトリックスをInDesignに転送する唯一の関数であり、それ自体では機能しないことが簡単にわかります。 反対の方向に進むこともできますが、変換マトリックスは常にデザインに転送する必要があり、変換された形状では機能しません。 しかし、残念なことに、デザインの手段で勾配を描くことができないため、そのような決定に至りました。

そして、C ++に戻って、プラグインのニュアンスを考慮してください。 ここには多くのコードがありますので、最も興味深い抜粋のみを提供し、些細なことやエラー処理を削除します。

始まりは明らかです:



  JNIEXPORT void JNICALL Java _..._ image
   (JNIEnv * env、jobject obj、 
   jintArray imageARGBBuff、jint x、jint y、jint width、jint height、
   jdoubleArray transformMatrix){

   K2 :: scoped_array <uint8> maskBuffer(新しいuint8 [imageARGBBuff.length]);
   K2 :: scoped_array <uint8> pictBuffer(新しいuint8 [3 * imageARGBBuff.length]);
A.

// ARGBのバッファを埋めます



しかし、その後タンバリンと踊りが始まります。

これは、ブレンディングカラースペース= RGBの場合、DesignはCMYKの画像を必要としているということです。 さもなければ、それは時間とともに落ち、主人公にひどい精神的な傷を負わせ、主人公が食べることすらできないほどになります。 そしてその逆-色空間をブレンドする= CMYKの場合、画像はRGBである必要があります。 これは実験的に発見されたものであり、なぜこのようにすべてが起こるのか-説明するのは難しいと思います。 したがって、現在設定している色空間を調べる必要があります。



  Utils <IXPUtils> xpUtils;
 InterfacePtr <IXPManager> xpManager(xpUtils-> QueryXPManager(db));
 InterfacePtr <IDocument> doc(db、db-> GetRootUID()、UseDefaultIID());
 AGMColorSpace * blendingSpace = xpManager-> GetDocumentBlendingSpace();
A.

必要に応じて変換します:



  uint8 * outBuff = nil;
 int16 compCnt = 3、スペース= kRGBColorSpace;

 if(IsBeingFlattened(env、obj)){
   TransformRGB2CMYKifNeeded(doc、blendingSpace、pictBuffer.get()、&outBuff、imageARGBBuff.length);
   compCnt = 4; スペース= kCMYKColorSpace;
   pictBuffer.reset(outBuff);
 } 
A.

これで、画像とアルファマスクの両方を設定する準備ができました。



  AGMImageRecord imgR;
 memset(&imgR、0、sizeof(AGMImageRecord));

 imgR.bounds.xMin = x;
 imgR.bounds.yMin = y;
 imgR.bounds.xMax = x + width;
 imgR.bounds.yMax = y + height;
 imgR.byteWidth = compCnt * width;
 imgR.colorSpace = space;
 imgR.bitsPerPixel = compCnt * 8;
 imgR.baseAddr =(void *)pictBuffer.get();

 AGMImageRecord maskR;
 memset(&maskR、0、sizeof(AGMImageRecord));
 maskR.bounds.xMin = x;
 maskR.bounds.yMin = y;
 maskR.bounds.xMax = x + width;
 maskR.bounds.yMax = y + height;
 maskR.byteWidth = width;
 maskR.colorSpace = kGrayColorSpace;
 maskR.bitsPerPixel = 8;
 maskR.baseAddr =(void *)maskBuffer.get();
A.

Java形式からInDesign形式への変換マトリックスを追い越すだけです。



  PMMatrix変換(nativeTransformData [0]、nativeTransformData [1]、
 nativeTransformData [2]、
    	 nativeTransformData [3]、 
 nativeTransformData [4]、 
 nativeTransformData [5]); 
A.

最後の仕上げ-アルファチャネルマスクに関する知識をアルファベットに伝える必要があります。



  AGMPaint * alphaServer = xpUt-> CreateImagePaintServer(&maskR、&transform、0、nil);
 PMRectの境界(x、y、幅+ x、高さ+ y); 




  port-> SetAlphaServer(alphaServer、kTrue、スタブ); 




  port-> starttransparencygroup(bounds、blendingSpace、kFalse、kFalse); 


そして、最終的に絵を描くことができます。 やった!



  port-> image(&imgR、transform、drawFlags); 
A.

アルファサーバーなどをクリーニングするためのコードは提供しません。これは簡単なためです。



最後の部分、または敗北したモンスターの宝物を取り出す

画像 このようにして、善良な仲間が三頭のヘビを倒すことができ、著者は、Adobe InDesign SDKで最も不十分に文書化されたタイプのプラグインの1つを既に描画してハリネズミ越えることができました。 残念ながら、たとえば同じ勾配など、改善の余地がありましたが、最終的な結果は非常に満足のいくものでした。

これで物語は終わりです。聞いた人は誰でもよくやった!



All Articles